python reduce找到集合的并集
Posted
技术标签:
【中文标题】python reduce找到集合的并集【英文标题】:python reduce to find the union of sets 【发布时间】:2013-11-26 18:09:36 【问题描述】:我正在尝试找到一组集合的并集。具体来说,我想要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'
我没有看到这个TypeError
,因为periodic_gs.keys()
是一个键列表(它们是字符串,但我不知道这有什么关系),当替换为lambda 函数的参数将起作用。
是什么导致了类型错误,我该如何解决?
【问题讨论】:
union of set of sets
: 一个集合不能包含另一个集合。
发布一些示例数据和预期输出。
【参考方案1】:
你可以像这样使用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()))
【讨论】:
不过,没有必要使用union()
。不适用于序列序列和空开头set()
。
*的文档在哪里?
@CodeKingPlusPlus What do *args and **kwargs mean?
@ChaimG 我也提供了答案。【参考方案2】:
是一个空的字典,而不是一个集合。使用
set()
创建一个空集。
但是,我认为您误解了reduce()
在这里的工作方式; x
是lambda
的上一个 返回值,y
是序列中的下一个值。因为你返回一个集合,x
在这里始终是一个集合,你不能将它用作periodic_gs
的键。
如果你想要图中所有个节点的联合,使用itertools.chain.from_iterable()
和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])
【讨论】:
现在是unhashable type: set
。
@CodeKingPlusPlus:您也使用了reduce错误;输出始终是一个集合,但您随后假设 x
是别的东西。【参考方案3】:
您的代码存在一些问题。您提供给reduce
、 的初始化程序是一个空的
dict
,而不是您似乎假设的set
,因此会导致第一种类型错误。然而,即使你解决了这个问题,还有一个更大的问题:lambda
的计算结果是一个包含节点的set
对象,然后这个set
被用作x
值,用于下一次调用@987654329 @,它试图将它当作periodic_gs
的键来使用,从而导致第二类错误。最重要的是,如果您只想使用它们来访问值,那么迭代 dict
的键是没有意义的;首先迭代这些值! 也将一堆列表转换为集合然后取它们的并集是没有意义的,因为你可以将它们全部链接在一起并取结果的并集。
我建议将代码完全重写为:
set(n for val in periodic_gs.values() for n in val.nodes())
【讨论】:
【参考方案4】:您可以使用 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])
【讨论】:
【参考方案5】:您不能拥有set
的set
,因为set
的元素需要是可散列的。但是,您可以创建 set
或 frozenset
。
frozenset(n) for val in periodic_gs.values() for n in val.nodes()
【讨论】:
以上是关于python reduce找到集合的并集的主要内容,如果未能解决你的问题,请参考以下文章