以python中任意数量列表的交集为例

以python中任意数量列表的交集为例,python,algorithm,list,intersection,Python,Algorithm,List,Intersection,假设我有一个相同元素列表(在本例中我将使用ints) 什么是一个好的和/或有效的方法来获取这些列表的交集(这样您就可以得到每个列表中的每个元素)? 例如: [0, 12, 24, 36, 48, 60, 72, 84, 96] 我认为内置的set模块应该可以做到这一点 >>> elements = [range(100)[::4], range(100)[::3], range(100)[::2], range(100)[::1]] >>> sets = m

假设我有一个相同元素列表(在本例中我将使用
int
s)

什么是一个好的和/或有效的方法来获取这些列表的交集(这样您就可以得到每个列表中的每个元素)? 例如:

[0, 12, 24, 36, 48, 60, 72, 84, 96]

我认为内置的
set
模块应该可以做到这一点

>>> elements = [range(100)[::4], range(100)[::3], range(100)[::2], range(100)[::1]]
>>> sets = map(set, elements)
>>> result = list(reduce(lambda x, y: x & y, sets))
>>> print result
[0, 96, 36, 72, 12, 48, 84, 24, 60]

将它们转换为集合,并使用
set.intersection
方法,减少集合列表中的:

xs = [range(100)[::4], range(100)[::3], range(100)[::2], range(100)[::1]]
reduce(set.intersection, [set(x) for x in xs])

reduce
是一种函数式编程设备,它迭代任何iterable并将提供的函数应用于前两个元素,然后应用于结果和下一个元素,然后应用于结果和下一个元素,依此类推。

您可以将它们视为集合并使用
set.intersection()


我要回答我自己的问题:

lists =  [range(100)[::4],range(100)[::3],range(100)[::2],range(100)[::1]]

out = set(lists[0])
for l in lists[1:]:
    out = set(l).intersection(out)

print out


使用具有交集方法的集合

>>> s = set()
>>> s.add(4)
>>> s.add(5)
>>> s
set([4, 5])
>>> t = set([2, 4, 9])
>>> s.intersection(t)
set([4])
举个例子,比如

>>> data = [range(100)[::4], range(100)[::3], range(100)[::2], range(100)[::1]]
>>> sets = map(set, data)
>>> print set.intersection(*sets)
set([0, 96, 36, 72, 12, 48, 84, 24, 60])

下面是一个使用良好的旧
all()
内置函数的单行程序:

list(num for num in data[0] 
     if all(num in range_ for range_ in data[1:]))


有趣的是,(我认为)对于更大的数据集,这比使用
set
更具可读性和速度更快。

你击败了我。我将保留我的答案,因为它适用于
reduce
稍微不同,但我很高兴看到其他人也从功能角度思考。:-)太多的学校通过直接跳转到Java来跳过(imho必修)函数式编程入门课程。伙计们,SCIP是有史以来最好的介绍CS的书……请注意,
set
是一种类型,而不是一个模块。(该集合类型以前位于名为
集合
的模块中,但长期以来一直被弃用。)尽管它非常优雅且工作正常,但它的速度似乎是不使用reduce的解决方案的两倍。有人知道为什么吗?这可能是因为必须构建更多的中间集。
set.intersection
将任意数量的可重用项作为参数(在最近的python中)。如果我没弄错的话,这可以用比
reduce
方法更高的算法复杂度来实现。@Mike:太棒了。我不知道。这会引起
名称错误
?我不这么认为,@MikeGraham。也许你指的是我编辑之前的代码。我运行了旧代码并得到了一个错误,但这段代码已经过测试并运行正常fine@inspectG4dget,我在编辑代码之前引用了该代码(我的注释看起来至少和编辑一样旧?)该代码不会存在该错误,但我必须承认我发现您的设计有点奇怪。@MikeGraham:我看到了编辑和注释的时间安排,这就是为什么我建议你的评论可能在编辑之前就已经发布了。但我很好奇你为什么会改变它的设计,以及如何改变它。@MikeGraham:非常正确。我曾想过这样做,但我希望我的代码更加透明——特别是因为我根本没有记录它。我不知道@thepandateMyFace有多熟练,因此我想让它尽可能简单。这会引起
AttributeError
?哎呀,
intersect
->
intersect
(已修复)。我将此作为最佳答案,因为它比我自己的速度快一点(反过来比使用reduce的速度快一倍)而且因为一次就有多台电视机的好处。谢谢或者,
set.intersection(set(x)表示数据中的x)
@thepandatemyface,我总是很高兴听到我的代码执行得很好,但也总是有点可疑。我相信这很大程度上取决于输入,如果输入的大小是个问题,你就没有时间在真正巨大的输入上运行它。如果我试图在大数据的内部循环中优化速度,我会考虑尝试<代码> SET(DATAS(0))。交叉(*DATAS(1:))<和代码>,它对我来说有一个很好的性能环。@ Mike Graham,我的意思是:在这里发布的所有优雅的解决方案中,你的速度最快。我很快用[[randint(0,100000)表示范围内的I(1000)]表示范围内的I(100)]作为我的数据对它进行了测试。这不是很科学,但它似乎一直以最快的速度提供您的项目。@David,您缺少一个
*(…)
来将生成器的项目作为参数应用。除此之外,这当然是一个很好的方法。我没有使用它的主要原因是为了强调,如果你在做像交叉点这样的操作,你可能已经有了集合。
print list(out)
>>> s = set()
>>> s.add(4)
>>> s.add(5)
>>> s
set([4, 5])
>>> t = set([2, 4, 9])
>>> s.intersection(t)
set([4])
>>> data = [range(100)[::4], range(100)[::3], range(100)[::2], range(100)[::1]]
>>> sets = map(set, data)
>>> print set.intersection(*sets)
set([0, 96, 36, 72, 12, 48, 84, 24, 60])
list(num for num in data[0] 
     if all(num in range_ for range_ in data[1:]))