Python 为列表中的每个唯一值指定一个数字
我有一个字符串列表。我想为每个字符串指定一个唯一的数字(确切的数字并不重要),并使用这些数字按顺序创建一个相同长度的列表。下面是我最好的尝试,但我不高兴有两个原因:Python 为列表中的每个唯一值指定一个数字,python,list,Python,List,我有一个字符串列表。我想为每个字符串指定一个唯一的数字(确切的数字并不重要),并使用这些数字按顺序创建一个相同长度的列表。下面是我最好的尝试,但我不高兴有两个原因: 它假定相同的值彼此相邻 我必须以0开始列表,否则输出将不正确 我的代码: names = ['ll', 'll', 'll', 'hl', 'hl', 'hl', 'LL', 'LL', 'LL', 'HL', 'HL', 'HL'] numbers = [0] num = 0 for item in range(len(names
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)
我想使代码更通用,这样它就可以处理未知列表。有什么想法吗?因为您要将字符串映射到整数,所以建议使用dict。因此您可以执行以下操作:
d = dict()
counter = 0
for name in names:
if name in d:
continue
d[name] = counter
counter += 1
numbers = [d[name] for name in names]
您也可以尝试以下方法:-
names = ['ll', 'll', 'll', 'hl', 'hl', 'hl', 'LL', 'LL', 'LL', 'HL', 'HL', 'HL']
indexList = list(set(names))
print map(lambda name:indexList.index(name),names)
无需使用外部库(检查编辑以获得
Pandas
解决方案),您可以按如下方式执行:
d = {ni: indi for indi, ni in enumerate(set(names))}
numbers = [d[ni] for ni in names]
简要说明:
在第一行中,为列表中的每个唯一元素分配一个数字(存储在字典d
;您可以使用字典理解轻松创建它;set
返回名称的唯一元素
)
然后,在第二行中,进行列表理解,并将实际数字存储在列表numbers
中
有一个例子可以说明它对未排序的列表也很有效:
# 'll' appears all over the place
names = ['ll', 'll', 'hl', 'hl', 'hl', 'LL', 'LL', 'll', 'LL', 'HL', 'HL', 'HL', 'll']
这是编号的输出:
[1, 1, 3, 3, 3, 2, 2, 1, 2, 0, 0, 0, 1]
如您所见,与ll
关联的编号1
出现在正确的位置
编辑
如果您有可用的,您也可以使用(这对于大型列表似乎非常有效,对于元组列表也非常有效,如前所述):
然后会回来
(array([(array([0, 0, 1, 1, 1, 2, 2, 0, 2, 3, 3, 3, 0]),
array(['ll', 'hl', 'LL', 'HL'], dtype=object))
所以,
numbers = pd.factorize(names)[0]
我设法稍微修改了您的脚本,看起来还可以:
names = ['ll', 'hl', 'll', 'hl', 'LL', 'll', 'LL', 'HL', 'hl', 'HL', 'LL', 'HL', 'zzz']
names.sort()
print(names)
numbers = []
num = 0
for item in range(len(names)):
if item == len(names) - 1:
break
elif names[item] == names[item+1]:
numbers.append(num)
else:
numbers.append(num)
num = num + 1
numbers.append(num)
print(numbers)
你们可以看到它非常相似,唯一的问题是,我为下一个元素添加了数字,而不是为当前元素添加了数字。这就是全部。哦,还有分类。它首先对大写字母进行排序,然后对小写字母进行排序。在本例中,如果希望更改,可以使用sort(key=lambda:x…
)。(可能是这样:names.sort(key=lambda x:(x.upper()如果x.lower()==x else x.lower())
)为了使其更通用,您可以将其包装在函数中,这样这些硬编码的值不会造成任何伤害,因为它们是本地的
如果使用高效的查找容器(我将使用普通字典),则可以保留每个字符串的第一个索引,而不会损失太多性能:
def your_function(list_of_strings):
encountered_strings = {}
result = []
idx = 0
for astring in list_of_strings:
if astring in encountered_strings: # check if you already seen this string
result.append(encountered_strings[astring])
else:
encountered_strings[astring] = idx
result.append(idx)
idx += 1
return result
这将按顺序分配索引(即使这并不重要):
这只需要在字符串列表上进行一次迭代,这样就可以处理生成器和类似的程序。如果条件是数字是唯一的,而确切的数字并不重要,则可以动态地将列表中的每个项目与唯一的数字相关联,并从count对象分配值:
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]
您可以通过在列表和count对象上使用,并将map函数设置为
{}.setdefault
(请参阅@StefanPochmann的注释)来删除额外的名称:
另外,如果已经安装了numpy,您还可以使用:
import numpy as np
_, numbers = np.unique(names, return_inverse=True)
print(numbers)
# [3 3 2 2 1 1 1 0 3]
如果有
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]
下面是一个类似于collections.defaultdict
和itertools.count
的解决方案:
import itertools as it
import collections as ct
names = ['ll', 'll', 'hl', 'hl', 'LL', 'LL', 'LL', 'HL', 'll']
dd = ct.defaultdict(it.count().__next__)
[dd[i] for i in names]
# [0, 0, 1, 1, 2, 2, 2, 3, 0]
每次新出现都会调用itertools.count
中的下一个整数,并将新条目添加到dd
中。熊猫可以简单地分解唯一的字符串:
将熊猫作为pd导入
代码,uniques=pd.factorize(名称)
代码
>>>数组([3,3,3,2,2,2,1,1,0,0,0])
这也可以通过LabelEncoder()
在Scikit学习中完成:
从sklearn导入预处理
le=预处理。LabelEncoder()
代码=le.fit_变换(名称)
代码
>>>数组([3,3,3,2,2,2,1,1,0,0,0])
在应用算法之前对列表进行排序怎么样如果你使用列表(map({}.setdefault,names,count())
,则不需要额外的变量。在第一种解决方案中,你可以使用len(d)
而不是next(c)
,a la:`numbers=[d.setdefault(i,len(d))来表示名称中的i]@StefanPochmann,是的,你也可以编写这个映射(indexList.index,name),如果不需要编写lambda
import numpy as np
_, numbers = np.unique(names, return_inverse=True)
print(numbers)
# [3 3 2 2 1 1 1 0 3]
>>> 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]
import itertools as it
import collections as ct
names = ['ll', 'll', 'hl', 'hl', 'LL', 'LL', 'LL', 'HL', 'll']
dd = ct.defaultdict(it.count().__next__)
[dd[i] for i in names]
# [0, 0, 1, 1, 2, 2, 2, 3, 0]