如何在Python中为列表分配序号的唯一值?

时间:2017-09-15 18:58:28

标签: python list unique

假设我有一个列表

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]

即。订单看起来是随机的,整个代码也很复杂。

有没有更简单的方法?

5 个答案:

答案 0 :(得分:1)

您可以尝试讨厌的(虽然比当前代码更容易理解),例如:

>>> 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)

答案 1 :(得分:1)

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]

答案 2 :(得分:1)

您是否希望订单由唯一元素的字母顺序或它们首次出现在原始列表中的顺序决定?例如,应该[' 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]

答案 3 :(得分:0)

似乎构建字典/映射是关键,使用它只是主题的变体。甚至构建字典也将是主题的变体 - 在读者眼中是否更好/更差/更简单/更复杂。

>>> 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]
>>>

如果a中的项目不在d中,则会抛出KeyException。

类似的,同样的警告:

>>> 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)

答案 4 :(得分:0)

我将假设: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(...)返回{{1} }}:False被忽略。

  • 案例2:看到x,因此xx in seen,第二部分进行评估。提醒False将始终返回seen.add,在此上下文中相当于NoneFalsex in seen or seen.add(x),但False已添加到x。并且seen返回not(...)True映射到x的len,每个新元素的增量为1.

第六行只是将新定义的字典映射到seen的值。