用空集合作为初始值的reduce

9 投票
6 回答
17872 浏览
提问于 2025-04-17 07:22

我有一个列表,里面又包含了多个子列表,我想从这些子列表中提取出所有的元素,构建一个集合。

举个例子:a = [[1,2],[2,3]] 这个列表应该能得到 set([1,2,3]),也就是一个包含1、2和3的集合。

我试过用 reduce(lambda x,y:x.update(y),a,set([])) 这个方法,但出现了一个错误,提示 AttributeError: 'NoneType' 对象没有 'update' 这个属性。

有没有人能告诉我怎么用 reduce 函数来实现这个功能呢?

6 个回答

2

Kindall已经回答了如何使用reduce()来完成这个任务,但我觉得用itertools.chain.from_iterable()的方法更简洁一些:

import itertools

a = [[1, 2], [2, 3]]

print set(itertools.chain.from_iterable(a))
16

根据要求:

>>> from functools import reduce
>>> a = [[1,2],[2,3]]
>>> reduce(lambda s, elems: s.union(elems), a, set())
set([1, 2, 3])

另外一种方法,纯粹是为了好玩:

>>> from itertools import chain
>>> set(chain.from_iterable(a))
set([1, 2, 3])

再来一种,纯粹是为了酷炫:

>>> set.union(set(), *a)
set([1, 2, 3])
9

问题在于,使用 update() 方法更新一个集合时,它会返回 None,而不是更新后的集合。这是文档中说明的,也是预期的行为。如果你确实想用 update(),你可以把你的 lambda 表达式写成这样:

 lambda x, y: x.update(y) or x

这里的 or 语句会在第一个条件为“假”的时候返回 x(而 None 就是“假”)。

不过,我觉得你其实应该用 union(),而不是 update()。它的功能基本相同,但会返回结果。

lambda x, y: x.union(y) 

顺便说一下,你可以直接写 set() 来获取一个空集合,不需要写 set([])。所以重写后的 reduce() 应该是:

reduce(lambda x, y: x.union(y), a, set())

其他人也提供了一些额外的选项,每个选项都有助于你思考它们的工作原理。

撰写回答