有效识别大型列表中的重复项(500,000 +)

时间:2017-05-25 23:51:53

标签: python list

我有一个很大的DOI列表,我需要最有效的方法来识别重复的DOI(即打印索引和重复值的DOI。) DOI的数组可以由500,000 + DOI组成。我目前的方法是这个(inspired by this answer):

from collections import defaultdict
D = defaultdict(list)
for i,item in enumerate(doiList):
    D[item].append(i)
D = {k:v for k,v in D.items() if len(v)>1}
print (D)

是否有更有效的处理方式?

样本DOI列表:

doiList = ['10.1016/j.ijnurstu.2017.05.011 [doi]','10.1016/j.ijnurstu.2017.05.011 [doi]' ,'10.1167/iovs.16-20421 [doi]', '10.1093/cid/cix478 [doi]', '10.1038/bjc.2017.133 [doi]', '10.3892/or.2017.5646 [doi]', '10.1177/0961203317711009 [doi]', '10.2217/bmm-2017-0087 [doi]', '10.1007/s12016-017-8611-x [doi]', '10.1007/s10753-017-0594-5 [doi]', '10.1186/s13601-017-0150-2 [doi]', '10.3389/fimmu.2017.00515 [doi]', '10.2147/JAA.S131506 [doi]', '10.2147/JAA.S128431 [doi]', '10.1038/s41598-017-02293-z [doi]', '10.18632/oncotarget.17729 [doi]', '10.1073/pnas.1703683114 [doi]', '10.1096/fj.201600857RRR [doi]', '10.1128/AAC.00020-17 [doi]', '10.1016/j.jpain.2017.04.011 [doi]', '10.1016/j.jaip.2017.04.029 [doi]', '10.1016/j.anai.2017.04.021 [doi]', '10.1016/j.alit.2017.05.001 [doi]']

2 个答案:

答案 0 :(得分:2)

尝试将它们存储在set中。您可以将重复项附加到单个列表中,这可能会加快速度:

seen = set()
dupes = []

for i, doi in enumerate(doiList):
    if doi not in seen:
        seen.add(doi)
    else:
        dupes.append(i)

此时,seen包含所有不同的doi值,而dupes包含重复值的所有第2,第3等索引。您可以在doiList中查找它们以确定哪个索引对应于哪个值。

为了获得更多性能,您可以缓存方法:

seen = set()
seen_add = seen.add
dupes = []
dupes_append = dupes.append

for i, doi in enumerate(doiList):
    if doi not in seen:
        seen_add(doi)
    else:
        dupes_append(i)

答案 1 :(得分:1)

这是一个完整的解决方案,可以返回与您的示例相同的数据集,速度提高两倍以上(以牺牲内存为代价):

def identify_duplicates(data):
    lookup = {}  # store our quick lookup here
    result = {}  # store for our final result
    for i, v in enumerate(data):
        if v in lookup:  # if already in the lookup table it's a duplicate
            if v not in result:  # add it to the result set
                result[v] = lookup[v]
            lookup[v][1] += 1  # increase duplicate count
        else:
            lookup[v] = [i, 0]  # default state for non-duplicates
    return result

print(identify_duplicates(doiList))
# prints: {'10.1016/j.ijnurstu.2017.05.011 [doi]': [0, 1]}

存储的索引是找到的副本的第一个匹配项,如示例中所示。如果要存储所有重复索引,可以在lookup[v].append(i)行之后添加lookup[v][1] += 1,但数据可能看起来很奇怪(结构将是[first_index, number_of_occurrences, second_index, third_index...]

相反,只需翻转lookup[v]修改中存储的参数 - lookup[v] = [0, i]而不是lookup[v] = [i, 0]lookup[v][0] += 1而不是lookup[v][1] += 1,然后lookup[v].append(i)它会以[number_of_occurrences, first_index, second_index, third_index...]的形式给你一个很好的结果。