【问题标题】:Dictionary of dictionaries: print dictionaries that share at least two common keys字典字典:打印至少共享两个公共键的字典
【发布时间】:2011-05-31 20:59:41
【问题描述】:
d = {'g1':{'p1':1,'p2':5,'p3':11,'p4':1},
     'g2':{'p1':7,'p3':1,'p4':2,'p5':8,'p9':11},
     'g3':{'p7':7,'p8':7},
     'g4':{'p8':9,'p9':1,'p10':7,'p11':8,'p12':3},
     'g5':{'p1':4,'p13':1},
     'g6':{'p1':4,'p3':1,'p6':2,'p13':1}
    }

对于给定的字典“d”,我想返回共享至少两个 ('n') 键的子字典簇(存在于给定簇的所有子字典中)。我们在这里不关心这些子字典的值。换句话说,给定簇中所有子字典的键的交集长度应该至少为两个(或'n')。

【问题讨论】:

  • 家庭作业?你试过什么?
  • 不是家庭作业;)我现在如何在 for 循环中为成对的键执行此操作,但不知道如何在全局范围内进行操作 - 全部反对。

标签: python dictionary key intersection


【解决方案1】:

我希望我能正确理解你想要什么。这种方法很笨拙,我担心它效率很低。

我在 d 中添加了一个字典 g6 以产生更有趣的输出:

#! /usr/bin/env python
# -*- coding: utf-8 -*-

d = {'g1':{'p1':1,'p2':5,'p3':11,'p4':1},
     'g2':{'p1':7,'p3':1,'p4':2,'p5':8,'p9':11},
     'g3':{'p7':7,'p8':7},
     'g4':{'p8':9,'p9':1,'p10':7,'p11':8,'p12':3},
     'g5':{'p1':4,'p13':1},
     'g6':{'p1':1,'p9':2,'p11':12}
    }

clusters = {}

for key, value in d.items ():
    cluster = frozenset (value.keys () )
    if cluster not in clusters: clusters [cluster] = set ()
    clusters [cluster].add (key)


for a in clusters.keys ():
    for b in clusters.keys ():
        if len (a & b) > 1 and a ^ b:
            cluster = frozenset (a & b)
            if cluster not in clusters: clusters [cluster] = set ()
            for x in clusters [a]: clusters [cluster].add (x)
            for x in clusters [b]: clusters [cluster].add (x)

print "Primitive clusters"
for key, value in filter (lambda (x, y): len (y) == 1, clusters.items () ):
    print "The dictionary %s has the keys %s" % (value.pop (), ", ".join (key) )

print "---------------------"
print "Non-primitive clusters:"
for key, value in filter (lambda (x, y): len (y) > 1, clusters.items () ):
    print "The dictionaries %s share the keys %s" % (", ".join (value), ", ".join (key) )

【讨论】:

    【解决方案2】:

    我认为您应该首先“反转”字典,然后很容易找到解决方案:

    import collections
    inverted = collections.defaultdict(list)
    
    for key, items in d.items():
        for sub_key in items:
            inverted[sub_key].append(key)
    
    for sub_key, keys in inverted.items():
        if len(keys) >= 2:
            print sub_key, keys
    

    【讨论】:

      【解决方案3】:

      类似

      for keya in d:
          tempd = {}
          keys = set()
          tempset = set(d[keya].keys())
      
          for keyb in d:
              tempset &= d[keyb].keys()
      
              if len(tempset) >= 2:
                  keys.add(keyb)
      
          print({key: d[key] for key in keys})
      

      可能会起作用。

      编辑:不,它不太有效。我需要考虑一下。

      【讨论】:

        【解决方案4】:

        如果您将问题简化为仅长度为 2 的集群(即字典对),它会变得更加清晰:从给定的可迭代对象生成固定长度的子序列正是 itertools.combinations 的工作:

        >>> list(itertools.combinations(d, 2))
        [('g5', 'g4'), ('g5', 'g3'), ('g5', 'g2'), ('g5', 'g1'), ('g4', 'g3'), ('g4', 'g
        2'), ('g4', 'g1'), ('g3', 'g2'), ('g3', 'g1'), ('g2', 'g1')]
        

        我们可以通过意识到视图 d.keys() 的行为类似于集合(在 Python 3 中;在 Python 2 中,它可能是一个列表)来查看任何字典共有的键的数量:

        >>> d['g1'].keys() & d['g2'].keys()
        {'p3', 'p1', 'p4'}
        

        & 是集合交集运算符 - 它为我们提供了这些集合共有的所有项目的集合。因此,我们可以通过检查这个集合的长度来检查其中至少有两个,这给了我们:

        >>> common_pairs = [[x,y] for x,y in itertools.combinations(d, 2)
                                           if len(d[x].keys() & d[y].keys()) >= 2]
        >>> common_pairs
        [['g2', 'g1']]
        

        解决未知的集群大小稍微困难一些 - 如果我们不对其进行硬编码,我们就不能直接使用 & 运算符。值得庆幸的是,set 类为我们提供了一种方法,以 set.intersection 的形式获取 n 个集合的交集。它不会接受 dict_keys 实例,但您可以通过调用 set 轻松解决此问题:

        >>> set.intersection(d['g1'].keys(), d['g2'].keys(), d['g5'].keys())
        Traceback (most recent call last):
          File "<stdin>", line 1, in <module>
        TypeError: descriptor 'intersection' requires a 'set' object but received a 'dict_keys'
        >>> set.intersection(set(d['g1']), set(d['g1']), set(d['g5']))
        {'p1'}
        

        您应该能够相当简单地将其推广到大小为 2 到 n 的集群。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-01-25
          • 2016-06-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多