17

我试图找到一组集合的并集。networkx具体来说,我想要图形字典中每个键的节点列表的联合称为periodic_gs. 我想使用该reduce功能,因为periodic_gs[x].nodes()x所有periodic_gs.

这是我的尝试:

reduce(lambda x,y: set(periodic_gs[x].nodes()).union(set(periodic_gs[y].nodes())), periodic_gs.keys(), {})

对我来说,这表示将字典中每个图形的节点联合起来。出于某种原因,python 告诉我:TypeError: unhashable type: 'dict'我看不到 this TypeError,因为periodic_gs.keys()它是一个键列表(它们是字符串,但我不知道这有什么关系),并且当替换为 lambda 函数的参数时将起作用。

是什么导致了类型错误,我该如何解决?

4

5 回答 5

36

你可以set.union这样使用:

>>> lis = [{1, 2, 3, 4}, {3, 4, 5}, {7, 3, 6}]
>>> set().union(*lis)
set([1, 2, 3, 4, 5, 6, 7])

可以使用 来执行此操作reduce,但不要

>>> reduce(set.union, lis)
set([1, 2, 3, 4, 5, 6, 7])

因为reduce由于它构建和丢弃的所有中间集,这需要二次时间:

In [1]: from functools import reduce

In [2]: sets = [{x} for x in range(1000)]

In [3]: %timeit set().union(*sets)
40.9 µs ± 1.43 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [4]: %timeit reduce(set.union, sets)
4.09 ms ± 587 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

这是这个测试用例的 100 倍减速,而且很容易变得更糟。

对于您的代码,应该这样做:

set().union(*(x.nodes() for x in periodic_gs.values()))
于 2013-11-13T22:36:48.933 回答
4

{}是一个空字典,而不是一个集合。用于set()创建空集。

但是,我认为您误解了reduce()这里的工作方式;x是 的上一个返回值lambda,并且y是序列中的下一个值。因为您返回一个集合,x所以在这里始终是一个集合,并且您不能将其用作periodic_gs.

如果您想要图中所有节点的并集,请使用itertools.chain.from_iterable()and set()

from itertools import chain

set(chain.from_iterable(periodic_gs[key].nodes() for key in periodic_gs))

这会从每个调用中创建一个集合。nodes()

要使用reduce()你必须考虑到第一个参数总是一个集合:

reduce(lambda res, key: res.union(periodic_gs[key].nodes()),  periodic_gs, set())

我在这里假设它periodic_gs是可迭代的(产生键),就像普通字典一样;如果没有,请使用periodic_gs.keys().

带有常规字典的快速演示:

>>> example = {'foo': [1,2,3], 'bar': [3, 4, 1]}
>>> reduce(lambda res, key: res.union(example[key]), example, set())
set([1, 2, 3, 4])
于 2013-11-13T22:27:29.257 回答
1

您的代码有几个问题。reduce您提供给,的初始化程序{}是空的dict,而不是set您似乎假设的 a ,因此导致第一个类型错误。然而,即使你解决了这个问题,仍然存在一个更大的问题:lambda计算到一个set包含节点的对象,然后 thisset被用作x下一次调用的值lambda,它试图使用它,就好像它是periodic_gs,从而导致第二类错误。dict最重要的是,如果您只想使用它们来访问值,那么迭代 a 的键是没有意义的。首先迭代这些值!还有_当您可以将它们全部链接在一起并合并结果时,将一堆列表转换为集合然后合并它们是没有意义的。

我建议将代码完全重写为:

set(n for val in periodic_gs.values() for n in val.nodes())
于 2013-11-13T22:31:14.787 回答
0

您可以使用 reduce 来获取多个集合的并集,如下所示:

>>> import operator
>>> a = set([1, 3, 5])
>>> b = set([2, 4, 6])
>>> c = set([0, 7, 8])
>>> reduce(operator.or_, [a, b, c])
set([0, 1, 2, 3, 4, 5, 6, 7, 8])
于 2013-11-13T22:36:33.213 回答
0

你不能有setofset因为set需要的元素是可散列的。set但是,您可以制作一个frozenset

{frozenset(n) for val in periodic_gs.values() for n in val.nodes()}
于 2013-11-13T23:33:02.333 回答