我有一个非唯一字符串列表:
list = ["a", "b", "c", "a", "a", "d", "b"]
我希望用一个整数键替换每个元素,以唯一标识每个字符串:
list = [0, 1, 2, 0, 0, 3, 1]
重要的是它是一个唯一标识符,而不是其数量。
到目前为止,我所想到的方法就是将列表复制到集合中,并使用集合的索引来引用列表。虽然我相信还有更好的方法。
这将确保唯一性,并且id从0
开始连续:
id_s = {c: i for i, c in enumerate(set(list))}
li = [id_s[c] for c in list]
另外值得注意的是,您不应该将 'list'
作为变量名称,因为它会掩盖内置类型 list
。
这是一个使用 defaultdict 的单遍解决方案:
from collections import defaultdict
seen = defaultdict()
seen.default_factory = lambda: len(seen) # you could instead bind to seen.__len__
In [11]: [seen[c] for c in list]
Out[11]: [0, 1, 2, 0, 0, 3, 1]
这有点诡计,但值得一提!
另一种方法,由@user2357112在相关的问题/答案中建议, 是使用itertools.count
递增。这允许您仅在构造函数中执行此操作:
from itertools import count
seen = defaultdict(count().__next__) # .next in python 2
default_factory
中使用那种反身力量。 - user2390182itertools.count().next
也可以用于default_factory
,或者您可以使用seen = defaultdict(lambda: len(seen))
,因为创建lambda时不需要存在seen
。我更喜欢itertools.count().next
而不是lambda: len(seen)
,因为它在可变操作中间不需要检查字典的状态,但是无论哪个版本都感觉default_factory
中有太多的魔法。 - user2357112__next__
),但我同意 itertools.count 比 len 好得多(虽然两者都是 O(1))。 - Andy Hayden>>> lst = ["a", "b", "c", "a", "a", "d", "b"]
>>> nums = [ord(x) for x in lst]
>>> print(nums)
[97, 98, 99, 97, 97, 100, 98]
如果您不挑剔,那么可以使用哈希函数:它返回一个整数。对于相同的字符串,它返回相同的哈希值:
li = ["a", "b", "c", "a", "a", "d", "b"]
li = map(hash, li) # Turn list of strings into list of ints
li = [hash(item) for item in li] # Same as above
l = ["a", "b", "c", "a", "a", "d", "b", "abc", "def", "abc"]
from itertools import count
from operator import itemgetter
mapped = itemgetter(*l)(dict(zip(l, count())))
from itertools import count
def uniq_ident(l):
cn,d = count(), {}
for ele in l:
if ele not in d:
c = next(cn)
d[ele] = c
yield c
else:
yield d[ele]
In [35]: l = ["a", "b", "c", "a", "a", "d", "b"]
In [36]: list(uniq_ident(l))
Out[36]: [0, 1, 2, 0, 0, 3, 1]
l = ["\t\t", "c"]
。 - Andy Hayden
list
作为变量名,因为它会遮盖内置的list
类型。这里不会有任何问题,但如果您的脚本稍后尝试使用list
类型构造列表,则可能会导致神秘的错误。 - PM 2Ring