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() 联合起来似乎是合理的,其中xperiodic_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() 在这里的工作方式; xlambda上一个 返回值,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】:

您不能拥有setset,因为set 的元素需要是可散列的。但是,您可以创建 setfrozenset

frozenset(n) for val in periodic_gs.values() for n in val.nodes()

【讨论】:

以上是关于python reduce找到集合的并集的主要内容,如果未能解决你的问题,请参考以下文章

Python实现求多个集合之间的并集

Python reduce() 函数

十二道MR习题 - 3 - 交集并集差集

java问题,求两个集合对象的并集

请问java有工具类取两个list的并集吗?

python内置函数filter(),map(),reduce()笔记