使用唯一索引索引列表

时间:2015-12-16 13:48:36

标签: python list indexing

我有一个名单l = [10,10,20,15,10,20]。我想为每个唯一值分配一个" index"得到[1,1,2,3,1,2]

这是我的代码:

a = list(set(l))
res = [a.index(x) for x in l]

结果证明非常慢。

l包含1M个元素和100K个唯一元素。我也尝试过使用lambda和排序的地图,这没有用。这样做的理想方式是什么?

6 个答案:

答案 0 :(得分:36)

您可以使用defaultdict和列表理解在O(N)时间内执行此操作:

>>> from itertools import count
>>> from collections import defaultdict
>>> lst = [10, 10, 20, 15, 10, 20]
>>> d = defaultdict(count(1).next)
>>> [d[k] for k in lst]
[1, 1, 2, 3, 1, 2]

在Python 3中使用__next__而不是next

如果您想知道它是如何运作的?

传递给default_factory的{​​{1}}仅在Python遇到缺失密钥时被调用,因此对于10,该值将为1,然后为在接下来的十年里,它不再是一个缺失的密钥,因此使用先前计算的1,现在20再次是一个缺失密钥,Python将再次调用count(1).next来获取其值,依此类推。

最后的

defaultdict将如下所示:

default_factory

答案 1 :(得分:21)

代码缓慢,因为a.index(x)执行线性搜索,并对l中的每个元素执行线性搜索。因此,对于您执行的每个1M项目(最多)进行100K比较。

将一个值转换为另一个值的最快方法是在地图中查找。您需要创建地图并填写原始值与所需值之间的关系。然后在列表中遇到另一个相同值时从地图中检索值。

这是一个通过l进行单次传递的示例。可能存在进一步优化的空间,以消除在追加时重复分配res的需要。

res = []
conversion = {}
i = 0
for x in l:
    if x not in conversion:
        value = conversion[x] = i
        i += 1
    else:
        value = conversion[x]
    res.append(value)

答案 2 :(得分:6)

您的解决方案很慢,因为它的复杂性为O(nm)m中的l中的唯一元素数量为a.index() O(m),您称之为l对于O(n)中的每个元素。

要使其成为index(),请删除>>> idx, indexes = 1, {} >>> for x in l: ... if x not in indexes: ... indexes[x] = idx ... idx += 1 ... >>> [indexes[x] for x in l] [1, 1, 2, 3, 1, 2] 并将索引存储在字典中:

l

如果quiz.js仅包含已知范围内的整数,您还可以将索引存储在列表中而不是字典中,以便更快地进行查找。

答案 3 :(得分:6)

嗯,我想这取决于你是否希望它以特定的顺序返回索引。如果您希望该示例返回:

    [1,1,2,3,1,2]

然后你可以查看提交的其他答案。但是,如果您只关心为每个唯一编号获取唯一索引,那么我有一个快速解决方案

    import numpy as np
    l = [10,10,20,15,10,20]
    a = np.array(l)
    x,y = np.unique(a,return_inverse = True)

并且对于此示例,y的输出为:

    y = [0,0,2,1,0,2]

我测试了1,000,000个条目并且它基本上立即完成。

答案 4 :(得分:2)

您可以使用collections.OrderedDict()按顺序保留唯一项目,并循环遍历此有序唯一项目的枚举,以获取项目和这些索引的字典(基于其顺序)然后通过这个字典包含operator.itemgetter()的主列表,以获取每个项目的相应索引:

>>> from collections import OrderedDict
>>> from operator import itemgetter
>>> itemgetter(*lst)({j:i for i,j in enumerate(OrderedDict.fromkeys(lst),1)})
(1, 1, 2, 3, 1, 2)

答案 5 :(得分:1)

对于完整性,你也可以急切地这样做:

from itertools import count

wordid = dict(zip(set(list_), count(1)))
     

这使用一个集合来获取list_对中的唯一单词   每个具有count()下一个值的唯一单词(其中   向上计数),并根据结果构建字典。

Original answer,由nneonneo撰写。