为列表中的每个唯一值分配一个数字

mil*_*lsy 13 python list

我有一个字符串列表.我想为每个字符串分配一个唯一的编号(确切的数字并不重要),并按顺序使用这些编号创建一个相同长度的列表.以下是我最好的尝试,但我不满意有两个原因:

  1. 它假设相同的值彼此相邻

  2. 我必须用a开始列表0,否则输出将是不正确的

我的代码:

names = ['ll', 'll', 'll', 'hl', 'hl', 'hl', 'LL', 'LL', 'LL', 'HL', 'HL', 'HL']
numbers = [0]
num = 0
for item in range(len(names)):
    if item == len(names) - 1:
      break
    elif names[item] == names[item+1]:
        numbers.append(num)
    else:
        num = num + 1
        numbers.append(num)
print(numbers)
Run Code Online (Sandbox Code Playgroud)

我想使代码更通用,因此它将使用未知列表.有任何想法吗?

Cle*_*leb 17

如果不使用外部库(检查编辑Pandas解决方案),你可以如下做到这一点:

d = {ni: indi for indi, ni in enumerate(set(names))}
numbers = [d[ni] for ni in names]
Run Code Online (Sandbox Code Playgroud)

简要说明:

在第一行中,为列表中的每个唯一元素指定一个数字(存储在字典中d;您可以使用字典理解轻松创建它; set返回唯一元素names).

然后,在第二行中,执行列表推导并将实际数字存储在列表中numbers.

一个例子来说明它也适用于未排序的列表:

# 'll' appears all over the place
names = ['ll', 'll', 'hl', 'hl', 'hl', 'LL', 'LL', 'll', 'LL', 'HL', 'HL', 'HL', 'll']
Run Code Online (Sandbox Code Playgroud)

这是输出numbers:

[1, 1, 3, 3, 3, 2, 2, 1, 2, 0, 0, 0, 1]
Run Code Online (Sandbox Code Playgroud)

如您所见,1与之关联的数字ll显示在正确的位置.

编辑

如果你有Pandas可用,你也可以使用pandas.factorize(这对于大型列表来说似乎非常有效,并且对于这里解释的元组列表也可以正常工作):

import pandas as pd

pd.factorize(names)
Run Code Online (Sandbox Code Playgroud)

然后会回来

(array([(array([0, 0, 1, 1, 1, 2, 2, 0, 2, 3, 3, 3, 0]),
 array(['ll', 'hl', 'LL', 'HL'], dtype=object))
Run Code Online (Sandbox Code Playgroud)

因此,

numbers = pd.factorize(names)[0]
Run Code Online (Sandbox Code Playgroud)


Mos*_*oye 6

如果条件是数字是唯一的并且确切的数字不重要,那么您可以构建一个映射,将列表中的每个项目动态地与唯一的数字相关联,从计数对象中分配值:

from itertools import count

names = ['ll', 'll', 'hl', 'hl', 'LL', 'LL', 'LL', 'HL', 'll']

d = {}
c = count()
numbers = [d.setdefault(i, next(c)) for i in names]
print(numbers)
# [0, 0, 2, 2, 4, 4, 4, 7, 0]
Run Code Online (Sandbox Code Playgroud)

您可以通过map在列表和计数对象上使用并将地图函数设置为{}.setdefault(请参阅@ StefanPochmann的注释)来取消额外的名称:

from itertools import count

names = ['ll', 'll', 'hl', 'hl', 'LL', 'LL', 'LL', 'HL', 'll']
numbers  = map({}.setdefault, names, count()) # call list() on map for Py3
print(numbers)
# [0, 0, 2, 2, 4, 4, 4, 7, 0]
Run Code Online (Sandbox Code Playgroud)

作为额外的,你也可以使用np.unique,以防你已经安装了numpy:

import numpy as np

_, numbers = np.unique(names, return_inverse=True)
print(numbers)
# [3 3 2 2 1 1 1 0 3]
Run Code Online (Sandbox Code Playgroud)

  • 如果你做`list(map({}.setdefault,names,count()))`则不需要额外的变量. (4认同)

Ste*_*ann 5

如果您有k不同的值,则会按照首次出现的顺序将它们映射0到整数:k-1

>>> names = ['b', 'c', 'd', 'c', 'b', 'a', 'b']
>>> tmp = {}
>>> [tmp.setdefault(name, len(tmp)) for name in names]
[0, 1, 2, 1, 0, 3, 0]
Run Code Online (Sandbox Code Playgroud)