如何将唯一值的序号分配给Python中的列表?

问题描述:

假设我有一个列表如何将唯一值的序号分配给Python中的列表?

A = ['A', 'A', 'A', 'B', 'B', 'C'] 

如何把它转化为

B = [0, 0, 0, 1, 1, 2] 

我写了这样

C = {t[1]:t[0] for t in enumerate(list(set(A)))} 
B = [C[e] for e in A] 

,它给了

[1, 1, 1, 2, 2, 0] 

即出现的顺序随机的,也是整个代码看起来复杂。

有没有更简单的方法?

+2

套件未订购。 –

+1

而不是'list(set(A))'(它以任意顺序创建一个列表),使用'sorted(set(A))'。 – DeepSpace

+0

您示例中的“A”中的项目是否只是大写字母?到目前为止的答案取决于这是数据的准确表示。 – roganjosh

你可以试一下讨厌(虽然比你当前的代码更易懂),如:

>>> B = [ord(x) - 65 for x in A] 
>>> B 
[0, 0, 0, 1, 1, 2] 

如果A是一个大名单,可以考虑让B是一个发电机,像这样:

B = (ord(x) - 65 for x in A) 
+0

字母只是例子。 – Dims

a = ['A', 'A', 'A', 'B', 'B', 'C'] 
x = sorted(set(a)) 
b = [x.index(y) for y in a] 
print(b) 
[0, 0, 0, 1, 1, 2] 
+0

对于长数组,这项工作会减慢吗? – Dims

您想要按照唯一元素的字母顺序或者它们首次出现在原始列表中的顺序来确定顺序吗?例如,如果['C','A','A','A','B','B','C']变成[2,0,0,0,1,1,2] ,或[0,1,1,1,2,2,0]?如果是前者:

uniques = list(set(A)) 
uniques.sort() 
uniques_dict = {uniques[i]:i for i in range(len(uniques))} 
B = [uniques_dict[a] for a in A] 

后者:

uniques_dict = {} 
ordinal = 0 
for a in A: 
    if not (a in uniques_dict.keys): 
    uniques_dict[a] = ordinal 
    ordinal = ordinal+1 
B = [uniques_dict[a] for a in A] 

好像构建字典/映射是关键,使用它将是一个主题的变化。即使构建字典也会是一个主题的变体 - 在读者眼中是否更好/更差/简单/复杂。

>>> import itertools 
>>> ordinatates = itertools.count(0) 
>>> a = ['a', 'b', 'c', 'a', 'a', 'c', 'c'] 
>>> unique = sorted(set(a)) 
>>> d = {thing:ordinal for thing, ordinal in zip(unique, ordinates)} 

应用它

>>> list(map(d.get, a)) 
[0, 1, 2, 0, 0, 2, 2] 
>>> 

它会抛出的KeyException如果在a不在d项目。

相似,同样的警告:

>>> import operator 
>>> a = ['a','b','c', 'a', 'a', 'c','c'] 
>>> m = map(operator.itemgetter, a) 
>>> [get(d) for get in m] 
[0, 1, 2, 0, 0, 2, 2] 
>>> 

类似无警告

class Foo(dict): 
    def __call__(self, item): 
     '''Returns self[item] or None.''' 
     try: 
      return self[item] 
     except KeyError as e: 
      # print or log something descriptive - print(repr(e)) 
      return None 

>>> ordinates = itertools.count(0) 
>>> a = ['a','b','c', 'a', 'a', 'c','c'] 
>>> unique = sorted(set(a)) 
>>> d = Foo((thing,ordinal) for thing, ordinal in zip(unique, ordinates)) 
>>> result = list(map(d, a)) 
>>> result 
[0, 1, 2, 0, 0, 2, 2] 
>>> 

所有这一切假设你想要的分类项的序号位置 - 为你的榜样名单是方便pre -sorted。如果您正在寻找在一个独特的东西第一次发生在列表中的位置,构建这样的映射:

import itertools 
ordinal = itertools.count() 
b = ['c','b','c', 'a', 'a', 'c','c'] 
d = {} 
for thing in b: 
    if thing in d: 
     continue 
    d[thing] = next(ordinal) 

应用

>>> list(map(d.get, b)) 
[0, 1, 0, 2, 2, 0, 0] 
>>> 

@Abdou提到这在他的评论,但你没方便回答。

如果您有可写为

d = {} 
d.update((thing,d[thing] if thing in d else next(ordinal)) for thing in b) 

一个班轮神物我会假设:1,你不依赖于要素是字母; 2.你想在列表A的第一次出现的基础上为它们编制索引。

>>> A = ['A', 'A', 'A', 'B', 'B', 'C'] 
>>> seen=set() 
>>> C={x:len(seen)-1 for x in A if not (x in seen or seen.add(x))} 
>>> C 
{'B': 1, 'C': 2, 'A': 0} 
>>> list(map(C.get, A)) 
[0, 0, 0, 1, 1, 2] 

第二行定义了一组,seen,将保存我们已经看到下一行的列表理解的A的元素。

第三行定义了将唯一元素映射到其索引的dictioanry。这有点棘手(虽然不是很不寻常)。

我们遍历A的值。

  • 情况1:值x是看到的那样,从而x in seen or ...True,第二部分不评估,和not(...)False返回:x被忽略。

  • 情况2:该值是x看到不,从而x in seenFalse和第二部分进行评价。提醒seen.add将始终返回None,在这种情况下相当于Falsex in seen or seen.add(x)False,但x已被添加到seen。并且not(...)返回Truex被映射到seen的len,对于每个新元素增加1。

第六行简单地映射新定义的字典的A值。