在Python中获取多个元组列表的第二个元素的交集的简单有效的方法?

2024-09-27 21:28:22 发布

您现在位置:Python中文网/ 问答频道 /正文

我是Python新手(在2.7中工作),我发现这是一个非常有价值的资源!在

假设我正在处理几个2元元组的列表,通常形式是(ID,value),例如

list1 = [(111, 222), (111, 333), (111, 444)]
list2 = [(555, 333), (555, 444), (555, 777)]
list3 = [(123, 444), (123, 888), (123, 999)]

我真正想做的是找到一个简单(并且计算效率高)的方法来得到这些元组的第二个元素的交集。我在Python docs中查看了一下,发现集合可以满足我的需要。。。this post有助于我理解如何得到两个列表的交集。在

我知道我可以通过这样的元组循环生成三个全新的“仅值”列表:

^{pr2}$

然后得到每对的交集如下:

i_of_1and2 = set(newList1).intersection(newList2)
i_of_1and3 = set(newList2).intersection(newList3)
i_of_2and3 = set(newList1).intersection(newList3)

但是我的列表有点大——比如几十万(有时几千万)的元组。这真的是获得这三个列表元组中第二个元素的交集的最佳方法吗?在我看来…不雅观。在

谢谢你的帮助!在


Tags: of方法id元素列表资源形式元组
3条回答

首先,您将看到一个很大的问题variable1通常是一个错误的符号-如果您想要有多个值,请使用一个数据结构,而不是使用很多带有编号名称的变量。这可以阻止你一遍又一遍地重复你的代码,并有助于阻止错误。在

让我们使用列表来代替:

values = [
    [(111, 222), (111, 333), (111, 444)],
    [(555, 333), (555, 444), (555, 777)],
    [(123, 444), (123, 888), (123, 999)]
]

现在我们只想得到子列表中每个元组的第二个元素。这很容易用list comprehension计算:

^{pr2}$

然后,我们需要这些项之间的交集,我们使用^{}得到两个可能的不同对:

>>> for values, more_values in itertools.combinations(new_values, 2):
...     set(values).intersection(more_values)
... 
{444, 333}
{444}
{444}

所以,如果我们把这个放在一起:

import itertools

values = [
    [(111, 222), (111, 333), (111, 444)],
    [(555, 333), (555, 444), (555, 777)],
    [(123, 444), (123, 888), (123, 999)]
]

sets_of_first_items = ({item[1] for item in sublist} for sublist in values)
for values, more_values in itertools.combinations(sets_of_first_items, 2):
    print(values.intersection(more_values))

这给了我们:

{444, 333}
{444}
{444}

我在这里所做的更改是使内部列表成为集合理解,避免创建一个列表只是为了将其转换为集合,并且使用生成器表达式而不是列表理解,因为它的计算是惰性的。在

最后一点,如果您想要我们用来生成交集的列表的索引,那么使用the ^{} builtin很简单:

sets_of_first_items = ({item[1] for item in sublist} for sublist in values)
for (first_number, first_values), (second_number, second_values) in itertools.combinations(enumerate(sets_of_first_items), 2):
    print("Intersection of {0} and {1}: {2}".format(first_number, second_number, first_values.intersection(second_values)))

这给了我们:

Intersection of 0 and 1: {444, 333}
Intersection of 0 and 2: {444}
Intersection of 1 and 2: {444}

编辑:

noted by tonyl7126一样,这也是一个可以通过使用更好的数据结构得到极大帮助的问题。这里最好的选择是使用一组产品id的dict。当你只需要一个集合,并打算稍后将其转换为集合时,没有理由将数据存储为一个列表,而dict对于你试图存储的数据类型是一个更好的解决方案。在

请参见以下示例:

import itertools

values = {
    "111": {222, 333, 444},
    "555": {333, 444, 777},
    "123": {444, 888, 999}
}

for (first_user, first_values), (second_user, second_values) in itertools.combinations(values.items(), 2):
    print("Intersection of {0} and {1}: {2}".format(first_user, second_user, first_values.intersection(second_values)))

给我们:

Intersection of 555 and 123: {444}
Intersection of 555 and 111: {444, 333}
Intersection of 123 and 111: {444}

您可以利用^{}方法获取2个或多个集合并找到它们的交集这一事实。另外,您可以使用list comprehensions来减少代码膨胀。最后,您可以使用argument list unpacking使其成为一行程序。例如:

>>> list1 = [(111, 222), (111, 333), (111, 444)]
>>> list2 = [(555, 333), (555, 444), (555, 777)]
>>> list3 = [(123, 444), (123, 888), (123, 999)]
>>>
>>> set.intersection(*[set(t[1] for t in l) for l in (list1, list2, list3)])
set([444])

为了帮助您理解发生了什么,对set.intersection(...)的调用等效于以下python代码:

^{pr2}$

我不确定您是否已经阅读过python中的词典,但这似乎适合您在结合列表时所做的工作。字典是由键和值组成的,就像你用2个元素元组模拟的一样。在

例如,list1、list2和list3可以表示为如下所示的字典(假设111是id): 你的字典={“111”:[222333,444],“555”:[333444777],“123”:[444888999]}

所以,如果你想得到一个特定id的所有值,比如“111”,你可以写下: 你的_dict.获取(“111”) 然后返回列表。这里是一些词典的链接。 http://docs.python.org/library/stdtypes.html#typesmapping

相关问题 更多 >

    热门问题