重用枚举创建的 Python 个对象

Reuse of Python object created by 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],[],[]]

如果我在内联 for 循环中包含枚举(参见下面的示例),我会收到正确的答案,但速度会显着降低。如何在不丢失存储在 enum_listA?

中的枚举信息的情况下执行此任务
for i in listA_set:
    listA_indices([j[0] for j in enumerate(listA) if j[1] == i])

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

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

不是,我完全不确定您的代码是如何工作的。你调用的是一个列表,一个不可调用的对象

listA_indices([...])

也许,你是故意的

listA_indices += [...] 

enumerate returns 一个只能迭代一次的迭代器。所以一旦它用完了,也就是你在第一次 for 循环迭代的列表理解中迭代它之后的情况,它就不会产生更多的项目。

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

enum_listA = list(enumerate(listA))

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

然而,您看到的性能差异来自于这样一个事实,即在第一次循环迭代之后,枚举器为空,因此列表理解不再运行以进行后续迭代。

使用 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 倍。