I have a list with n elements:
['pea', 'rpai', 'rpai', 'schiai', 'pea', 'rpe', 'zoi', 'zoi', 'briai', 'rpe']
I have to assign a number to each string, zero at the start, and then increment by one if the element is different, instead give the same number if the element repeats. Example:
['pea', 'rpai', 'rpai', 'schiai', 'pea', 'rpe', 'zoi', 'zoi', 'briai', 'rpe']
[ 0, 1, 1, 2, 0, 3, 4, 4, 5, 3 ]
How can I do it?
Try this:
a = ['pea', 'rpai', 'rpai', 'schiai', 'pea', 'rpe', 'zoi', 'zoi', 'briai', 'rpe']
dct = {}
counter = 0
for i in range(len(a)):
if a[i] not in dct.keys():
dct[a[i]] = counter
counter += 1
print([(i, dct[i]) for i in a])
You just need to proof if you had it already
def counts(final):
count3 = [] # contains all objects that were already found
count2=[]
count=0
for x in final:
if x not in count3: # test if it's not already in count3
count+=1
count2.append(count)
count3.append(x)
else:
count2.append(count)
return count2
using a dictionary would achieve this.
def counts(a):
dis = {}
count=0
for i in range(len(a)):
if a[i] not in dis.keys():
dis[a[i]] = count
count+=1
return([dis[x] for x in a])
With a helper dict:
>>> [*map({k: v for v, k in enumerate(dict.fromkeys(final))}.get, final)]
[0, 1, 1, 2, 0, 3, 4, 4, 5, 3]
Another way:
>>> d = {}
>>> [d.setdefault(x, len(d)) for x in final]
[0, 1, 1, 2, 0, 3, 4, 4, 5, 3]
I was proven wrong and I have to use a dictionary (thanks @Steve). Here's the updated version with dictionary included:
a = ['pea', 'rpai', 'rpai', 'schiai', 'pea', 'rpe', 'zoi', 'zoi', 'briai', 'rpe']
b = [None]*len(a)
d = {}
for i,x in enumerate(a):
if x not in d: d[x] = len (d) #or use d.setdefault(x, len(d)) instead of the if statement (using the algo from @superb rain's)
b[i] = d[x]
print (a)
print (b)
The output of this will be:
['pea', 'rpai', 'rpai', 'schiai', 'pea', 'rpe', 'zoi', 'zoi', 'briai', 'rpe']
[0, 1, 1, 2, 0, 3, 4, 4, 5, 3]
Use a defaultdict and use a counter as a default value function.
Whenever the key exists, it returns the stored "first encountered position", otherwise it calls Incr.__call__ which increments its count to provide a new first encountered position.
With super brain's suggestion, use an existing counter class:
from collections import defaultdict
from itertools import count
li = ['pea', 'rpai', 'rpai', 'schiai', 'pea', 'rpe', 'zoi', 'zoi', 'briai', 'rpe']
seen = defaultdict(count().__next__)
print( [seen[val] for val in li] )
Rolling my own Incr, as before, which does give you the advantage that you could return anything (such as a GUID):
from collections import defaultdict
class Incr:
def __init__(self):
self.count = -1
def __call__(self):
self.count +=1
return self.count
li = ['pea', 'rpai', 'rpai', 'schiai', 'pea', 'rpe', 'zoi', 'zoi', 'briai', 'rpe']
seen = defaultdict(Incr())
print( [seen[val] for val in li] )
[0, 1, 1, 2, 0, 3, 4, 4, 5, 3]
Cleanest way might be to use pandas:
import pandas as pd
lst = ['pea', 'rpai', 'rpai', 'schiai', 'pea', 'rpe', 'zoi', 'zoi', 'briai', 'rpe']
pd.factorize(lst)
Which outputs:
(array([0, 1, 1, 2, 0, 3, 4, 4, 5, 3], dtype=int64),
array(['pea', 'rpai', 'schiai', 'rpe', 'zoi', 'briai'], dtype=object))