比较python中Gigantic Two Dimen列表中一个列表的值,最快的方式?

时间:2010-11-30 23:58:11

标签: python performance list comparison list-comprehension

我想比较一个列表的值是否存在于其他列表的值中。它们是巨大的(50k +项目,来自数据库)。

编辑:

我还想将重复的记录标记为duplicate = True,并将它们保存在表中以供日后参考。

这里列表如何:

n_emails=[db_id,checksum for id,checksum in search_results]
#I want to compare checksum if exist inside same list or other list and retrieve id (db_id , if exist)
#example : n_emails= [[1,'CAFEBABE010'],[2,'bfeafe3df1ds],[3,'deadbeef101'],[5,'CAFEBABE010']] 
#in this case i want to retrive id 1 and 5 coz they are same checksum

for m in n_emails:
    dups=_getdups(n_emails,m[1],m[0])           
    n_dups=[casesdb.duplicates.insert( **dup ) for dup in dups]
    if n_dups:
        print "Dupe Found"
        casesdb(casesdb.email_data.id == m[0]).update(duplicated=True)

def _getdups(old_lst,em_md5,em_id):
    dups=[]
    for old in old_lst:
        if em_md5==old[0] and old[1]!=em_id:
            dups.append(dict(org_id=old[1],md5hash=old[0],dupID=em_id,))
    return dups

但它似乎太长了并且在更大的列表中(50k vs 50k记录+)它运行超过5000秒并且从未完成,似乎永远不会结束循环? 我运行的服务器有4 GB的内存和4个内核。显然我做错了。

请帮助..非常感谢!

解决:

Dict Index Mapping速度快得多! (当没有索引mysql表时,请注意我没有测试索引表)。

它的20秒vs 30毫秒= 20 * 1000/30 = 666次! LOL

4 个答案:

答案 0 :(得分:2)

你最好用SQL查找重复项。例如,请参阅this page describing how to find duplicates

将所有这些结果提取到Python中并处理它们的速度永远不会很快,但如果必须,最好的办法是给ID校验和字典:

got_checksums = {}
for id, checksum in emails:
    if checksum in got_checksums:
        print id, got_checksums[checksum]
    else:
        got_checksums[checksum] = id

答案 1 :(得分:2)

最快的方法是使用这样的字典:

n_emails= [[1,'CAFEBABE010'],[2,'bfeafe3df1ds'],[3,'deadbeef101'],[5,'CAFEBABE010']]

d = {}
for id, hash in n_emails:
    if hash not in d:
        d[hash] = [id]
    else:
        d[hash].append(id)

for hash, ids in d:
    if len(ids) > 1:
       print hash, ids

这几乎是散列连接的算法


for hash, count in select hash, count(id) as num from emails group by num having num > 1:
    first = None
    for index, id in enumerate(select id from emails where hash=hash sort by desc id):
        if index == 0:
            first = id
            continue
        update emails set duplicate=first where id=id

将是sql / python解决方案,我将重复列并使用它来存储哪一条消息被认为是重复的

电子邮件表至少是:

create table emails (id, hash, duplicate default null)

答案 2 :(得分:2)

你做错了是:

  • 您可以直接从数据库中获取结果。它比Python快得多。
  • 您正在对校验和进行线性搜索,这意味着每个50k条目都与其他50k条目中的每个进行比较......这是大量的比较。

您应该做的是在校验和上构建索引。制作一张映射checksum -> entry的字典。插入条目时检查校验和是否已存在,如果是,则条目重复。

或者你只是使用你的数据库,他们喜欢索引。

答案 3 :(得分:1)

最后,感谢所有答案,我发现dict映射速度非常快!比SQL查询快得多。

这是我的SQL查询测试(它看起来很尴尬,但它是Web2pyDAL查询的语法)。

我测试了3500条记录,并且仅针对超过250000条记录进行了dict映射。

print "de_duping started at %s" % str( datetime.datetime.now() )

dupe_n = 0
l_dupe_n = 0
for em_hash in n_emails:
    dup_ids=casesdb(casesdb.email_data.MD5Hash==em_hash[1]).select(casesdb.email_data.id)
    if dup_ids>1:
        dupe_n+=1

print "Email Dupes %s" % (dupe_n)
print "Local de_duping ended at %s" % str( datetime.datetime.now() )

Resullts in:

de_duping started at 2010-12-02 03:39:24.610888
Email Dupes 3067
Local de_duping ended at 2010-12-02 03:39:52.669849
大约28秒 继承人基于Dan D的基于dict的索引图

    print "de_duping started at %s" % str( datetime.datetime.now() )
    for id, hash in em_hash:

            if hash not in dedupe_emails:

                dedupe_emails[hash] = [id]
            else:

                dedupe_emails[hash].append( id )
                dupe_n += 1
                casesdb( casesdb.email_data.id == id ).update( duplicated = True )

    print "Email Dupes %s" % (dupe_n)
    print "Local de_duping ended at %s" % str( datetime.datetime.now() )

结果:

de_duping started at 2010-12-02 03:41:21.505235
Email Dupes 2591 # this is accurate as selecting from database regards first match as duplicate too
Local de_duping ended at 2010-12-02 03:41:21.531899
只有什么? 30毫秒!

让我们看看它对重复删除250k记录做了什么!

de_duping at 2010-12-02 03:44:20.120880
Email Dupes 93567 
Local de_duping ended at 2010-12-02 03:45:12.612449

不到一分钟!!

感谢所有答案,我想选择那些指出我正确方法的人,但Dan D给了我最详细的答案!谢谢Dan!