<pre class="lang-python prettyprint-override"><code>import itertools
A = {'E2': {'5', '7'}, 'E3': {'4', '8'}, 'E5': {'5', '7'}, 'E8': {'4', '8'}}
def key(x):
# List supports ordering
return sorted(list(x[1]))
def gen():
for (group_key, group) in itertools.groupby(sorted(A.items(), key=key), key=key):
gl = list(group)
yield (tuple(x[0] for x in gl),
gl[0][1] # group_key is a list, but we want original set
)
print(dict(gen()))
</code></pre>
<p>如果您已经准备好让自己相信set->;list->;set conversion是安全的,那么您可以使用一个liner代替generator:</p>
^{pr2}$
<p>那么,到底发生了什么?</strong></p>
<p>首先,我们通过调用<code>.items()</code>将dict转换为元组的iterable。
我们想将这个iterable的项目组合在一起,这个iterable具有相同的第二个元素(索引为1,或者前一个dict值)。
这正是<code>itertools.groupby</code>所做的。这些论点是一个重要的和关键的,我们将据此进行分组。看起来,<code>key=lambda kv: kv[1]</code>是一条路。不幸的是没有。我们可以比较集合的相等性,但是文档说iterable应该被排序。和<code>sorted</code>函数需要键comparable for order。无法比较集合,因为“排序依据”列表可以。我们可以安全地创建一个包含与set相同元素的列表,但是我们应该对它进行排序(相等的集合可以产生顺序不同的列表,<code>{5, 7} == {7, 5}</code>,但是<code>[5, 7] != [7, 5]</code>)。在</p>
<p>现在,经过排序和分组,我们得到了以下数据结构:</p>
<pre><code>[
(key_dict_value as list, iterable of (dict_key, dict_value) that has dict_value == key_dict_value),
...
]
</code></pre>
<p>现在我们可以迭代这个iterable并创建另一个元组的iterable。我们获取每个元组的第二个元素(iterable,索引为1)并将其转换为一个元组(这是我们未来字典的关键)。我们未来词典的价值是源于原始词典的价值。我们可以从元组的第二个元素的某个元素中获取它(这个iterable不能为空,因为<code>groupby</code>不能生成空组,请参见第一个片段),或者从{<cd8>}将其转换回list(这是安全的,因为这个列表是从集合中生成的,所以它没有相等的元素,请参见第二个片段)。在</p>
<p><strong>UPD2</strong></p>
<p>在编写解释时,我发现等式键对于<code>sorted</code>不合适,但对于<code>groupby</code>来说很好,因此这里有一个更简单的解决方案,不需要定义<code>key</code>函数并将list转换回set:</p>
<pre><code>print(dict((tuple(g[0] for g in group), group_key) for
(group_key, group) in itertools.groupby(sorted(A.items(),
key=lambda x: sorted(list(x[1]))),
key=lambda x: x[1])))
</code></pre>