【问题标题】:How to find repeats or duplicates in nested dictionary?如何在嵌套字典中查找重复项或重复项?
【发布时间】:2019-07-09 02:57:13
【问题描述】:

我有一个嵌套字典,我正在尝试在其中查找重复项。例如,如果我有:

dictionary = {'hello': 3 , 'world':{'this': 5 , 'is':{'a': 3, 'dict': None}}}

返回值类似于:

True

因为这本词典包含重复项。

我可以很容易地用普通字典做到这一点,我认为这也适用于这种情况:

dictionary = {'hello': 3 , 'world':{'this': 5 , 'is':{'a': 3, 'dict': None}}}
rev_dictionary = {}

for key, value in dictionary.items():
    rev_dictionary.setdefault(value, set()).add(key)
    print(rev_dictionary)

for key,values in dictionary.items():
    if len(values) > 1:
        values = True
    else:
        values = False

这会引发以下错误:

TypeError: unhashable type: 'dict'

我怎样才能让它工作?

感谢您的帮助!

注意:如果可能,我更喜欢不使用库的解决方案

【问题讨论】:

  • Define "duplicates." 在我看来,即使给我{"1": {"CPU": "AMD", "OS": "Linux", "Hostname": "spicy-tequila"}, "2": {"CPU": "AMD", "OS": "Linux", "Hostname": "coy-wolves"}},它们仍然是两个不同的对象,尽管它们有一些共同点。

标签: python dictionary


【解决方案1】:

我写了一个简单的解决方案:

dictionary = {'hello': 3 , 'world':{'this': 5 , 'is':{'a': 3, 'dict': None}}}

def get_dups(a, values=None):
    if values is None: values = []
    if (a in values): return True
    values.append(a)
    if type(a) == dict:
        for i in a.values():
            if (get_dups(i, values=values)):
                return True
    return False

print(get_dups(dictionary))

工作原理

我们首先将每个value 保存在一个列表中,我们将把它传递给函数。 每次运行我们都会检查我们的当前值是否在该列表中,一旦有重复值就返回True

if (a in values): return True

接下来,如果当前索引也是字典,我们只需遍历这些值并对它们运行get_dups

【讨论】:

    【解决方案2】:

    我认为您只需要在传递到重复检测管道之前将 dict 展平:

    import pandas as pd
    
    def flatten_dict(d):
        df = pd.io.json.json_normalize(d, sep='_')
        return df.to_dict(orient='records')[0]
    
    dictionary = {'hello': 3 , 'world':{'this': 5 , 'is':{'a': 3, 'dict': None}}}
    
    dictionary = flatten_dict(dictionary)
    print('flattend')
    print(dictionary)
    
    rev_dictionary = {}
    
    for key, value in dictionary.items():
        rev_dictionary.setdefault(value, set()).add(key)
    
    print('reversed')
    print(rev_dictionary)
    
    is_duplicate = False
    for key, values in rev_dictionary.items():
        if len(values) > 1:
            is_duplicate = True
            break
    
    print('is duplicate?', is_duplicate)
    

    结果:

    flattend
    {'hello': 3, 'world_is_a': 3, 'world_is_dict': None, 'world_this': 5}
    reversed
    {3: {'hello', 'world_is_a'}, None: {'world_is_dict'}, 5: {'world_this'}}
    is duplicate? True
    

    扁平化字典的代码来自:Flatten nested Python dictionaries, compressing keys

    【讨论】:

      【解决方案3】:

      您可以递归地将子字典的项目值添加到集合中,如果集合中已经“看到”任何项目值,则引发异常,以便包装器可以返回 True 以指示找到了一个骗子:

      def has_dupes(d):
          def values(d):
              seen = set()
              for k, v in d.items():
                  if isinstance(v, dict):
                      s = values(v)
                      if seen & s:
                          raise RuntimeError()
                      seen.update(s)
                  else:
                      if v in seen:
                          raise RuntimeError()
                      seen.add(v)
              return seen
          try:
              values(d)
          except RuntimeError:
              return True
          return False
      

      因此,给定您的样本输入,has_dupes(dictionary) 将返回:True

      【讨论】:

        【解决方案4】:

        我假设您是按值而不是按键定义重复项。在这种情况下,您可以使用 (mentioned here) 来展平嵌套的字典

        def flatten(d):
            out = {}
            for key, val in d.items():
                if isinstance(val, dict):
                    val = [val]
                if isinstance(val, list):
                    for subdict in val:
                        deeper = flatten(subdict).items()
                        out.update({key + '_' + key2: val2 for key2, val2 in deeper})
                else:
                    out[key] = val
            return out
        

        然后检查条件

        v = flatten(d).values()
        len(set(v))!=len(v)
        

        结果为真

        【讨论】:

          【解决方案5】:

          将嵌套字典转换为其值的嵌套列表:

          def nested_values(v):
              return map(nested_values, v.values()) if isinstance(v, dict) else v
          

          然后将嵌套列表展平为字典中所有值的列表, 然后检查扁平的重复值列表:

          from itertools import chain
          
          def is_duplicated_value(d):
              flat = list(chain.from_iterable(nested_values(d)))
              return len(flat) != len(set(flat))
          

          测试:

          print is_duplicated_value( {1:'a', 2:'b', 3:{1:'c', 2:'a'}} )
          print is_duplicated_value( {1:'a', 2:'b', 3:{1:'c', 2:'d'}} )
          

          输出:

          True
          False
          

          根据您的使用和字典大小等,您可能希望将这些步骤重新转换为递归函数,将每个值添加到 set,然后检查每个值是否在集合中,然后立即添加和返回 True 或 @ 987654327@ 如果字典用完了。

          class Duplicated(ValueError): pass
          
          def is_dup(d):
              values = set()
              def add(v):
                  if isinstance(v, dict):
                      map(add, v.values())
                  else:
                      if v in values:
                          raise Duplicated
                      else:
                          values.add(v)
              try:
                  add(d)
                  return False
              except Duplicated:
                  return True
          

          测试:

          print is_dup( {1:'a', 2:'b', 3:{1:'c', 2:'a'}} )
          print is_dup( {1:'a', 2:'b', 3:{1:'c', 2:'d'}} )
          

          输出:

          True
          False
          

          【讨论】:

            猜你喜欢
            • 2019-01-15
            • 2021-11-17
            • 2022-01-09
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-12-26
            相关资源
            最近更新 更多