对列表中的每对元素进行操作


94

使用Python,我想比较列表中的每个可能的对。

假设我有

my_list = [1,2,3,4]

我想对列表中2个元素的每个组合进行一个操作(我们称之为foo)。

最终结果应与

foo(1,1)
foo(1,2)
...
foo(4,3)
foo(4,4)

我的第一个想法是手动遍历列表两次,但这似乎并不十分精妙。

Answers:


229

product()itertools模块中签出。它完全符合您的描述。

import itertools

my_list = [1,2,3,4]
for pair in itertools.product(my_list, repeat=2):
    foo(*pair)

这等效于:

my_list = [1,2,3,4]
for x in my_list:
    for y in my_list:
        foo(x, y)

编辑:有两个非常相似的功能,以及,permutations()combinations()。为了说明它们之间的区别:

product() 生成所有可能的元素对,包括所有重复项:

1,1  1,2  1,3  1,4
2,1  2,2  2,3  2,4
3,1  3,2  3,3  3,4
4,1  4,2  4,3  4,4

permutations()生成每个唯一元素对的所有唯一排序,从而消除x,x重复项:

 .   1,2  1,3  1,4
2,1   .   2,3  2,4
3,1  3,2   .   3,4
4,1  4,2  4,3   .

最后,combinations()仅按字典顺序生成每个唯一的元素对:

 .   1,2  1,3  1,4
 .    .   2,3  2,4
 .    .    .   3,4
 .    .    .    .

这三个函数都是在Python 2.6中引入的。


1
奇怪的是,当我运行itertools.product(my_list,2)时,它抱怨int不可调用。一旦我将其更改为即可工作:itertools.product(my_list,repeat = 2)
ojrac,2009年

注意itertools.product()是Python 2.6中的新增功能。
Mike Mazur,2009年

仅出于后代目的,我将指出itertools.combinations在原始示例中不会生成foo(1,1)或foo(4,4)行。
Kylotan

2
也有combinations_with_replacement()。与combinations()类似,但包括对角线(与插图保持一致)。
Ziegl

1
对于懒惰:要获得上述结果permutations()combinations()使用r=2的替代repeat=2的例子使用product()
罗布

15

我有一个类似的问题,在这里找到了解决方案。它的工作无需导入任何模块。

假设一个列表如下:

people = ["Lisa","Pam","Phil","John"]

简化的单行解决方案如下所示。

所有可能的对,包括重复项:

result = [foo(p1, p2) for p1 in people for p2 in people]

所有可能的对,但重复项除外

result = [foo(p1, p2) for p1 in people for p2 in people if p1 != p2]

唯一对,其中顺序无关:

result = [foo(people[p1], people[p2]) for p1 in range(len(people)) for p2 in range(p1+1,len(people))]

如果您不想操作而只想获取对,则删除该函数foo并仅使用一个元组就足够了。

所有可能的对,包括重复项:

list_of_pairs = [(p1, p2) for p1 in people for p2 in people]

结果:

('Lisa', 'Lisa')
('Lisa', 'Pam')
('Lisa', 'Phil')
('Lisa', 'John')
('Pam', 'Lisa')
('Pam', 'Pam')
('Pam', 'Phil')
('Pam', 'John')
('Phil', 'Lisa')
('Phil', 'Pam')
('Phil', 'Phil')
('Phil', 'John')
('John', 'Lisa')
('John', 'Pam')
('John', 'Phil')
('John', 'John')

所有可能的对,但重复项除外

list_of_pairs = [(p1, p2) for p1 in people for p2 in people if p1 != p2]

结果:

('Lisa', 'Pam')
('Lisa', 'Phil')
('Lisa', 'John')
('Pam', 'Lisa')
('Pam', 'Phil')
('Pam', 'John')
('Phil', 'Lisa')
('Phil', 'Pam')
('Phil', 'John')
('John', 'Lisa')
('John', 'Pam')
('John', 'Phil')

唯一对,其中顺序无关:

list_of_pairs = [(people[p1], people[p2]) for p1 in range(len(people)) for p2 in range(p1+1,len(people))]

结果:

('Lisa', 'Pam')
('Lisa', 'Phil')
('Lisa', 'John')
('Pam', 'Phil')
('Pam', 'John')
('Phil', 'John')

编辑:进行了简化以简化此解决方案的工作后,我意识到它与Adam Rosenfield是相同的方法。我希望更大的解释能帮助一些人更好地理解它。


2
我非常喜欢此方法,而不是导入一个更干净的库!
sudo-nim

itertools是Python的一部分。它不是外部库。
GuiSim

2

如果您只是调用一个函数,那么您实际上做不到以下事情:

for i in my_list:
    for j in my_list:
        foo(i, j)

如果要收集调用函数结果的列表,可以执行以下操作:

[foo(i, j) for i in my_list for j in my_list]

这将为您返回适用foo(i, j)于每个可能对的结果列表(i, j)


0
my_list = [1,2,3,4]

pairs=[[x,y] for x in my_list for y in my_list]
print (pairs)

尽管此代码可能会解决这个问题,一个很好的答案还需要解释什么代码的功能以及如何它解决了问题。
BDL
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.