你一开始就表现出一个大问题variable1
通常是一个不好的迹象 - 如果你想有多个值,请使用数据结构,而不是大量带有编号名称的变量。这可以防止您一遍又一遍地重复您的代码,并有助于阻止错误。
让我们使用列表列表来代替:
values = [
[(111, 222), (111, 333), (111, 444)],
[(555, 333), (555, 444), (555, 777)],
[(123, 444), (123, 888), (123, 999)]
]
现在我们只想获取子列表中每个元组的第二个元素。使用列表推导很容易计算:
>>> [[item[1] for item in sublist] for sublist in values]
[[222, 333, 444], [333, 444, 777], [444, 888, 999]]
然后,我们想要项目之间的交集,我们itertools.combinations()
用来获得两个可能的各种对:
>>> 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}
我在这里所做的更改是使内部列表成为集合推导,以避免创建列表只是为了将其转换为集合,并使用生成器表达式而不是列表推导,因为它是惰性求值的。
最后一点,如果您想要我们用来生成交集的列表的索引,使用内置enumerate()
函数很简单:
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}
编辑:
正如tonyl7126所指出的,这也是一个可以通过使用更好的数据结构得到很大帮助的问题。这里最好的选择是将用户 ID 的字典用于一组产品 ID。当您只需要一个集合并且稍后将其转换为集合时,没有理由将您的数据存储为列表,并且 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}