重用由枚举创建的Python对象

时间:2016-02-03 21:55:29

标签: python enumerate

我有一个列表,我正在搜索以找到重复的索引。

listA = [[1,2,3],[3,4,5],[6,7,8],[1,2,3]]
listA_set = [[1,2,3],[3,4,5],[6,7,8]]
enum_listA = enumerate(listA)
listA_indices = []
for i in listA_set:
    listA_indices([j[0] for j in enum_listA if j[1] == i])

预期结果是:

listA_indices = [[0,3],[1],[2]]

但相反,我得到了:

listA_indices = [[0,3],[],[]]

如果我在in-line for循环中包含枚举(参见下面的示例),我会收到正确的答案,但会看到速度显着降低。如何在不丢失存储在enum_listA中的枚举信息的情况下执行此任务?

for i in listA_set:
    listA_indices([j[0] for j in enumerate(listA) if j[1] == i])

3 个答案:

答案 0 :(得分:2)

enumerate返回一个只能迭代一次的迭代器。因此,一旦它耗尽,在第一次for循环迭代的列表理解中迭代它之后就会出现这种情况,它将不再产生任何项目。

如果要保留信息,则必须将该数据实际存储在内存中,例如列表:

enum_listA = list(enumerate(listA))

请注意,这会有效地复制列表中的信息并添加索引,因此这会浪费大量额外内存,并且最终可能不会比重复使用枚举对象更有效。

然而,您看到的性能差异来自以下事实:在第一次循环迭代之后,枚举数为空,因此列表推导不再为后续迭代运行。

答案 1 :(得分:1)

使用dictset,您的代码将更有效地运行:

from collections import defaultdict

st = set(map(tuple, listA_set))
d = defaultdict(list)

for i, ele in enumerate(map(tuple,listA)):
    if ele in st:
        d[ele].append(i)

print(list(d.items()))

print(list(d.values()))

输出:

[((3, 4, 5), [1]), ((6, 7, 8), [2]), ((1, 2, 3), [0, 3])]
[[1], [2], [0, 3]]

如果您想维持首次看到的订单:

from collections import  OrderedDict
d = OrderedDict()

for i, ele in enumerate(map(tuple, listA)):
    if ele in st:
        d.setdefault(ele, []).append(i)

print(list(d.items()))

print(list(d.values()))

输出:

[((1, 2, 3), [0, 3]), ((3, 4, 5), [1]), ((6, 7, 8), [2])]
[[0, 3], [1], [2]]

无论你使用枚举的方式,你的复杂性仍然是二次方的,这将比你自己的方法快得多。

随机数据集的某些时间:

In [27]: from random import randint

In [28]: listA_set = [[randint(1,20) for _ in range(10)] for _ in range(2000)]

In [29]: listA = [[randint(1,20) for _ in range(10)] for _ in range(3000)]

In [30]: %%timeit
listA_indices = []
for i in listA_set:
    listA_indices.append([j[0] for j in enumerate(listA) if j[1] == i])
   ....: 
1 loops, best of 3: 696 ms per loop

In [31]: %%timeit
st = set(map(tuple, listA_set))
from collections import  OrderedDict
d = OrderedDict()
for i, ele in enumerate(map(tuple,listA)):
    if ele in st:
        d.setdefault(ele, []).append(i)
   ....: 
1000 loops, best of 3: 1.49 ms per loop

~400次更快。

答案 2 :(得分:0)

您看到速度显着降低(根据您的术语)的原因是您的第二个正确版本实际上正在计算您正在寻找的值。

因为枚举产生一个生成器,一旦你消耗它的值,你就不能再生成它们了。您提供的第二个版本是使用枚举的正确方法。

方面没有,我不确定你的代码是如何工作的。您正在调用列表,一个不可调用的对象

listA_indices([...])

也许,你打算做

listA_indices += [...]