【问题标题】:Invert a dictionary of multiple sets反转多个集合的字典
【发布时间】:2016-12-11 22:41:55
【问题描述】:

假设我有一个集合的字典:

DictofSets={
    'Key1':set(['A', 'B', 'D', 'F']),
    'Key2':set(['B', 'C', 'G']),
    'Key3':set(['A', 'B', 'D', 'F']),
    'Key4':set(['A', 'B', 'C', 'D', 'F']),
    'Key5':set(['A', 'B', 'E', 'F'])}

现在假设我想在多个集合中找到集合元素的键。

我能做的最好的事情是:

from collections import Counter

# first get counts of elements in excess of 1:
c=Counter()
for s in DictofSets.values():
    c+=Counter(s)

# dict of lists for the keys if the set item occurs more than once
inverted={k:[] for k, v in c.items() if v>1} 
for k in sorted(DictofSets):
    for e in DictofSets[k]:
        if e in inverted:
            inverted[e].append(k)

它会产生我想要的东西:

>>> inverted
{'A': ['Key1', 'Key3', 'Key4', 'Key5'], 
 'C': ['Key2', 'Key4'], 
 'B': ['Key1', 'Key2', 'Key3', 'Key4', 'Key5'], 
 'D': ['Key1', 'Key3', 'Key4'], 
 'F': ['Key1', 'Key3', 'Key4', 'Key5']}

但这似乎有点笨拙。有没有更简单的方法来做到这一点?

【问题讨论】:

  • 已有答案here
  • 寻找更好的方法来创建inverted:inverted = {k: [] for k,v in Counter(chain(*DictofSets.values())).items() if v > 1}。至于最后的循环,我想不出另一种方式 atm 但我觉得不太笨拙。

标签: python python-3.x dictionary set


【解决方案1】:

我认为 OP 方法没有任何问题。它可以更简洁地表达,但这并没有使它变得更好:

>>> import itertools as it
>>> c = Counter(it.chain.from_iterable(DictofSets.values()))
>>> {l: {k for k, s in DictofSets.items() if l in s} for l, n in c.items() if n > 1}
{'A': {'Key1', 'Key3', 'Key4', 'Key5'},
 'B': {'Key1', 'Key2', 'Key3', 'Key4', 'Key5'},
 'C': {'Key2', 'Key4'},
 'D': {'Key1', 'Key3', 'Key4'},
 'F': {'Key1', 'Key3', 'Key4', 'Key5'}}

【讨论】:

  • 应该改用[k for k, s in sorted(DictofSets.items()) if l in s] 来保持排序(因为它似乎是必需的),我个人会使用chain.from_iterablechain 来获得计数器初始化的减速带。跨度>
  • 如果需要sorted,OP 显示,那么像 OP 那样在循环中执行可能会更好。同意chain
【解决方案2】:

这是 defaultdict 的工作

>>> DictofSets={
    'Key1':set(['A', 'B', 'D', 'F']),
    'Key2':set(['B', 'C', 'G']),
    'Key3':set(['A', 'B', 'D', 'F']),
    'Key4':set(['A', 'B', 'C', 'D', 'F']),
    'Key5':set(['A', 'B', 'E', 'F'])}
>>> from collections import defaultdict
>>> SetsofDicts = defaultdict(set)
>>> for key, values in DictofSets.items():
        for x in values:
            SetsofDicts[x].add(key)


>>> from pprint import pprint
>>> pprint(SetsofDicts)
defaultdict(<class 'set'>,
            {'A': {'Key3', 'Key1', 'Key5', 'Key4'},
             'B': {'Key3', 'Key1', 'Key5', 'Key2', 'Key4'},
             'C': {'Key4', 'Key2'},
             'D': {'Key3', 'Key1', 'Key4'},
             'E': {'Key5'},
             'F': {'Key3', 'Key1', 'Key5', 'Key4'},
             'G': {'Key2'}})
>>> 

一旦你明白了,删除不需要的条目很容易,并且有很多方法可以做到这一点,例如

>>> for toremove in [ k for k,v in SetsofDicts.items() if len(v)<=1 ]:
        del SetsofDicts[toremove]


>>> pprint(SetsofDicts)
defaultdict(<class 'set'>,
            {'A': {'Key3', 'Key1', 'Key5', 'Key4'},
             'B': {'Key3', 'Key1', 'Key5', 'Key2', 'Key4'},
             'C': {'Key4', 'Key2'},
             'D': {'Key3', 'Key1', 'Key4'},
             'F': {'Key3', 'Key1', 'Key5', 'Key4'}})
>>>     

【讨论】:

  • 根据 OP 输出,不应包含具有单个匹配项的条目。
  • @JimFasarakis-Hilliard 有很多方法可以删除不需要的条目,我包括了一个
  • 当然,不知道这是否可以被认为比 OPs 解决方案“更容易”,但无论哪种方式都是主观的。
  • @JimFasarakis-Hilliard 好吧,通过使用集合,我不必担心检查我是否已经使用了某个键,并且一切都可以在一个字典中完成,而不是 2 作为 OP正在做
  • 是的,但是通过使用集合,您会失去排序(OP 似乎希望通过sorted(DictofSets) 判断)。无论哪种方式,OP实际上都有最终决定权,我只是在观察(我并没有真正发现他的解决方案如此“笨拙”:P)
猜你喜欢
  • 1970-01-01
  • 2022-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-03
  • 1970-01-01
相关资源
最近更新 更多