2016-02-03 47 views
2

我有一個列表,我正在通過搜索來找到重複的索引。通過枚舉創建Python對象的重用

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],[],[]] 

如果我包括內嵌的循環中枚舉(見下例),我收到正確的答案,但看到速度顯着降低。我該如何執行此任務而不會丟失enum_listA中存儲的枚舉信息?

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

「我收到正確的答案,但看到速度顯着降低」 - 從不比較正確的代碼和無用的錯誤代碼的性能。如果你沒有問題,你可以在任何時候做任何事。 – user2357112

回答

2

enumerate返回一個只能使用一次迭代的迭代器。所以一旦耗盡了,在你迭代第一次for循環迭代的列表理解之後就會發生這種情況,它將不會產生更多的項目。

如果你想保留的信息,你將有實際存儲在內存中的數據,例如一個列表:

enum_listA = list(enumerate(listA)) 

注意,這有效地複製在列表中的信息,並添加索引,所以這會浪費大量額外的內存,並且可能不會比重複創建枚舉對象更高效。

然而,您所看到的性能差異來自於第一次循環迭代之後,枚舉器爲空,因此列表理解不再運行用於後續迭代。

0

您看到速度顯着降低(通過您的術語)的原因是您的第二個正確版本實際上是在計算您正在查找的值。

因爲枚舉會生成一個生成器,所以一旦使用了它的值,就不能再生成它們。你提出的第二個版本是使用枚舉的正確方法。

不是,我不知道你的代碼是如何工作的。要調用列表,不可贖回對象

listA_indices([...]) 

也許,你的意思做

listA_indices += [...] 
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倍。

+0

感謝您的建議。我實現了這種方法,它看起來工作得很好(我對結構化列表還是比較新的,所以它通常不是我的默認方法)。 –