从字典列表中删除重复项

3

我目前能够在嵌套字典前面没有键的情况下去除重复项。这个函数可以用于以下字典列表示例:

 [{'asndb_prefix': '164.39.xxx.0/17',
  'cidr': '164.39.xxx.0/17',
  'cymru_asn': 'XXX',
  'cymru_country': 'GB',
  'cymru_owner': 'XXX , GB',
  'cymru_prefix': '164.39.xxx.0/17',
  'ips': ['164.39.xxx.xxx'],
  'network_id': '164.39.xxx.xxx/24',},
 {'asndb_prefix': '54.192.xxx.xxx/16',
  'cidr': '54.192.0.0/16',
  'cymru_asn': '16509',
  'cymru_country': 'US',
  'cymru_owner': 'AMAZON-02 - Amazon.com, Inc., US',
  'cymru_prefix': '54.192.144.0/22',
  'ips': ['54.192.xxx.xxx', '54.192.xxx.xxx'],
  'network_id': '54.192.xxx.xxx/24',
  }]

def remove_dict_duplicates(list_of_dicts):
    """
    "" Remove duplicates in dict 
    """
    list_of_dicts = [dict(t) for t in set([tuple(d.items()) for d in list_of_dicts])]
    # remove the {} before and after - not sure why these are placed as 
    # the first and last element 
    return list_of_dicts[1:-1]

然而,我希望能够根据键和该字典中关联的所有值删除重复项。因此,如果存在相同的键但值不同,则不应将其删除,但如果存在完全一样的副本,则应将其删除。

    [{'50.16.xxx.0/24': {'asndb_prefix': '50.16.0.0/16',
   'cidr': '50.16.0.0/14',
   'cymru_asn': 'xxxx',
   'cymru_country': 'US',
   'cymru_owner': 'AMAZON-AES - Amazon.com, Inc., US',
   'cymru_prefix': '50.16.0.0/16',
   'ip': '50.16.221.xxx',
   'network_id': '50.16.xxx.0/24',
   'pyasn_asn': xxxx,
   'whois_asn': 'xxxx'}},
   // This would be removed
   {'50.16.xxx.0/24': {'asndb_prefix': '50.16.0.0/16',
   'cidr': '50.16.0.0/14',
   'cymru_asn': 'xxxxx',
   'cymru_country': 'US',
   'cymru_owner': 'AMAZON-AES - Amazon.com, Inc., US',
   'cymru_prefix': '50.16.0.0/16',
   'ip': '50.16.221.xxx',
   'network_id': '50.16.xxx.0/24',
   'pyasn_asn': xxxx,
   'whois_asn': 'xxxx'}},
   // This would NOT be removed
   {'50.16.xxx.0/24': {'asndb_prefix': '50.999.0.0/16',
   'cidr': '50.999.0.0/14',
   'cymru_asn': 'xxxx',
   'cymru_country': 'US',
   'cymru_owner': 'AMAZON-AES - Amazon.com, Inc., US',
   'cymru_prefix': '50.16.0.0/16',
   'ip': '50.16.221.xxx',
   'network_id': '50.16.xxx.0/24',
   'pyasn_asn': xxxx,
   'whois_asn': 'xxxx'}}]

我该如何去做呢?谢谢。


什么键?你给它一个列表,列表没有键... - Willem Van Onsem
字典不允许重复的键。 - Christian Dean
抱歉,我可能误用了术语。在第二个代码块中,'23.21.xxx.0/24'不是被认为是一个关键吗? - John Z
这个程序中重复的元素在哪里? - ospahiu
在第二个代码块中更新了我的示例。 - John Z
2个回答

6

从字典列表中删除重复项:

list_of_unique_dicts = []
for dict_ in list_of_dicts:
    if dict_ not in list_of_unique_dicts:
        list_of_unique_dicts.append(dict_)

非常感谢。我也很惊讶 "in" 这样工作的方式。 - John Z

2

如果结果中的顺序不重要,您可以使用集合将字典转换为冻结集来删除重复项:

def remove_dict_duplicates(list_of_dicts):
    """
    Remove duplicates.
    """
    packed = set(((k, frozenset(v.items())) for elem in list_of_dicts for
                 k, v in elem.items()))
    return [{k: dict(v)} for k, v in packed]

假设所有最内层字典的值都是可哈希的。

放弃顺序可以为大型列表带来潜在的加速。例如,创建一个有100,000个元素的列表:

inner = {'asndb_prefix': '50.999.0.0/16',
         'cidr': '50.999.0.0/14',
         'cymru_asn': '14618',
         'cymru_country': 'US',    
         'cymru_owner': 'AMAZON-AES - Amazon.com, Inc., US',    
         'cymru_prefix': '50.16.0.0/16',    
         'ip': '50.16.221.xxx',    
         'network_id': '50.16.xxx.0/24',    
         'pyasn_asn': 14618,    
          'whois_asn': '14618'}

large_list = list_of_dicts + [{x: inner} for x in range(int(1e5))]

反复检查结果列表中的重复项需要花费相当长的时间:

def remove_dupes(list_of_dicts):
    """Source: answer from wim
    """ 
    list_of_unique_dicts = []
    for dict_ in list_of_dicts
        if dict_ not in list_of_unique_dicts:
            list_of_unique_dicts.append(dict_)
    return list_of_unique_dicts

%timeit  remove_dupes(large_list
1 loop, best of 3: 2min 55s per loop

我的方法是使用集合,速度会稍微快一些:

%timeit remove_dict_duplicates(large_list)
1 loop, best of 3: 590 ms per loop

你应该提到这种方法的额外限制:所有的值都必须是可哈希的。 - wim
是的,看起来原始方法也是这样假设的。 - Mike Müller
这个确实可行,但它不能像你说的那样保持顺序。我相信我选择作为答案的方法对我的应用程序最好。 - John Z
但如果你的列表很大,它可以更快。 - Mike Müller
我同意。我会百分之百记住这个。目前来看,这个列表很容易管理。感谢解释! - John Z

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接