4

免责声明:我不是经验丰富的 Python 用户。

我遇到了一个任务,现在我正试图找出用 Python 完成它的最优雅的方法。

这是任务本身:给定一个list字符串返回一个ints 列表(每个int从 0 到 N - 1,其中 N 是列表中唯一字符串的数量),其中每个 int 对应于初始列表中的某个字符串。相同的字符串应该映射到相同的数字,不同的字符串 - 映射到不同的数字。

我想出的第一件事似乎“有点”过于复杂:

a = ["a","b","a","c","b","a"]
map(lambda x: dict(map(lambda x: reversed(x), enumerate(set(a))))[x], a)

上面代码的结果:

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

5 回答 5

4

您可以使用 dict 和列表推导:

>>> a = ["a","b","a","c","b","a"]
>>> d = {x:i for i, x in enumerate(set(a))}
>>> [d[item] for item in a]
[0, 2, 0, 1, 2, 0]

为了保持秩序:

>>> seen = set()
>>> d = { x:i for i, x in enumerate(y for y in a
                                       if y not in seen and not seen.add(y))}
>>> [d[item] for item in a]
[0, 1, 0, 2, 1, 0]

上面的dict理解等价于:

>>> seen = set()
>>> lis = []
for item in a:
    if item not in seen:
        seen.add(item)
        lis.append(item)
...         
>>> lis
['a', 'b', 'c']
>>> d = {x:i for i,x in enumerate(lis)}
于 2013-09-16T10:41:08.573 回答
2

如果您想保留接近字符的顺序,我认为您使用 set 的方法可能会导致错误。实际上你可以在你的例子中看到它 - 'b'got index2而不是1. 如果你想保持秩序,你可以使用OrderedDict

>>> a = ["a","b","a","c","b","a"]
>>> d = {x:i for i, x in enumerate(OrderedDict(izip(a, a)).values())}
>>> [d[x] for x in a]
[0, 1, 0, 2, 1, 0]
于 2013-09-16T10:43:35.980 回答
1

强调可读性,而不是速度:我会使用index带有列表理解的 list 方法:

>>> a = ["a","b","a","c","b","a"]
>>> b = list(set(a))
>>> c = [b.index(x) for x in a]
>>> c
[0, 2, 0, 1, 2, 0]
于 2013-09-16T10:43:35.183 回答
0

您也可以使用 defaultdict 和 count 迭代器来完成。

>>> from collections import defaultdict
>>> from itertools import count
>>> a = ["a","b","a","c","b","a"]
>>> x = defaultdict(count().next)
>>> [x[i] for i in a]
[0, 1, 0, 2, 1, 0]
于 2013-09-16T11:31:45.813 回答
0

首先从列表中获取唯一的字符串并枚举它,因此每个字符串都有一个数字(从 0 到 N-1)。然后为每个字符串获取此值,并将其放入列表中。这是它是如何完成的,在一行中:

a = ["a","b","a","c","b","a"]
[{s:i for i, s in enumerate(set(a))}[s] for s in a]
于 2013-09-16T10:45:21.000 回答