比较2个dicts,如果值相同但键不同,则在python中将键添加到新列表

时间:2013-06-20 17:28:19

标签: python dictionary comparison

我有一个递归遍历2个目录的程序,并将文件名:sha256hash放入2个dicts,folder1和folder2。

我想要做的是对哈希进行比较,如果哈希匹配但密钥不同,则将密钥发布到名为“重命名”的新列表中。我有逻辑来解释已删除的文件,新文件和密钥相同但文件(哈希)不同的文件(修改后的文件),但在我的生活中不能让我自己去做相反。

    # Put filename:hash into 2 dictionaries from the folders to compare

    for root, dirs, files in os.walk(folder_1):
        for file in files:
            files1[file] = get_hash(os.path.join(root,file))

    for root, dirs, files in os.walk(folder_2):
        for file in files:
            files2[file] = get_hash(os.path.join(root, file))

    # Set up the operations to do for the comparison 

    set_files2, set_files1 = set(files2.keys()), set(files1.keys())
    intersect = set_files2.intersection(set_files1)

    # Compare and add to list for display

    created.extend(set_files2 - intersect)
    deleted.extend(set_files1 - intersect)
    modified.extend(set(k for k in intersect if files1[k] != files2[k]))
    unchanged.extend(set(k for k in intersect if files1[k] == files2[k]))

这个的问题是1:它不考虑重命名的文件,2:它将重命名的文件放入创建中,所以一旦我重命名文件,我必须创建=创建 - 重命名以过滤掉实际新文件中的文件

感谢任何/所有帮助。我走到这一步,但出于某种原因,我的思绪正在罢工。

3 个答案:

答案 0 :(得分:3)

您可以翻转files1files2字词:

name_from_hash1 =  {v:k for k, v in file1.items()}
name_from_hash2 =  {v:k for k, v in file2.items()}

(我在this SO answer找到的翻转成语。)

然后,

renamed = []
for h in name_from_hash1:
    if h in name_from_hash2 and name_from_hash1[h] != name_from_hash2[h]:
        renamed.append(name_from_hash2[h])

renamed是按其当前名称重命名的文件名列表。您可以通过在最后一行中将name_from_hash2更改为name_from_hash来获取重命名文件的原始名称列表。

答案 1 :(得分:2)

我有一个简单的解决方案:不是将文件名作为键和哈希作为值,而是将哈希作为键和文件名作为值(毕竟,您希望键是唯一的,而不是值) 。您只需调整程序的其余部分即可。 (糟糕,看起来像Bitwise在评论中已经提到过了。哦,好吧。)

如果您不想更改代码的其余部分,如果您使用的是Python 2.7 +,这里有一个很好的单行方法来创建一组重命名的文件:

renamedfiles = {k for k, v in hashes1.items() if v in hashes2.values()}

为了略微提高Python 2.7的效率,请改用iteritems()itervalues()(默认情况下,Python 3将其键,项和值视图表示为迭代器)。

附录:您也可以执行renamedfiles = filter(lambda item:item in hashes2.values(), hashes1.items()),但这会导致对符合条件的键/值对而不是集合或词典的迭代器。此外,我认为即使filter()是内置方法之一,但在Python中通常更喜欢理解。

答案 2 :(得分:0)

这是一个很快出现的错误的多项式时间解决方案,但是:

>>> d1 = {'a':1, 'b':2, 'c':3}    
>>> d2 = {'a':1, 'b':3, 'c':2}
>>> for key1 in d1:
...     for key2 in d2:
...             if d1[key1] == d2[key2] and key1 != key2:
...                     print key1, key2
... 
c b
b c

此代码打印d2中的密钥,其值与d1中的密钥相同,但前提是两个密钥不同。对此进行调整,以便将更改后的密钥放在modified列表中。