如何将列表中的每个项目与其余项目进行一次比较?


73

假设我有一个数组/要比较的事物列表。在我更熟悉的语言中,我会做类似的事情

for (int i = 0, i < mylist.size(); i++)
    for (int j = i + 1, j < mylist.size(); j++)
        compare(mylist[i], mylist[j])

这样可以确保我们只比较每对一次。在某些情况下,我正在对列表中包含的一堆对象进行碰撞检测。对于检测到的每个碰撞,将一个描述碰撞的小的“碰撞”对象添加到列表中,然后另一个例程循环循环以解决每个碰撞(取决于两个碰撞对象的性质)。显然,我只想报告每个碰撞一次。

现在,这样做的pythonic方式是什么,因为Python倾向于使用迭代器而不是遍历索引?

我有以下(越野车)代码:

for this in mylist:
    for that in mylist:
        compare(this, that)

但这显然会使每次碰撞发生两次,从而在尝试解决它们时导致一些奇怪的行为。那么这里的pythonic解决方案是什么?


我不确定“比较”是什么意思。我要做的是将一个列表放在哈希表中,然后在第二个列表上循环。在每次迭代中,我都会进行比较。
路易丝

Answers:


128

当然,这将生成每对两次,因为每个for循环将遍历列表的每个项目。

您可以在这里使用一些itertools魔术来生成所有可能的组合:

import itertools
for a, b in itertools.combinations(mylist, 2):
    compare(a, b)

itertools.combinations 会在迭代中将每个元素与另一个元素配对,但只能配对一次。


您仍然可以使用基于索引的项目访问(与您以前使用的嵌套for循环相同)来编写此代码:

for i in range(len(mylist)):
    for j in range(i + 1, len(mylist)):
        compare(mylist[i], mylist[j])

当然,这看起来可能不那么好用,但是有时它仍然是最简单,最易理解的解决方案,因此您不应该回避解决此类问题。


大!感谢您的解释和链接。我不知道itertools模块,但它看起来很方便。
Bogdanovist,

@pokename 'compare' is not defined我该如何补救?
3kstc

1
@ 3kstc我从问题中得到了这一点。将其替换为您想要对每对项目执行的操作。

@poke-金发碧眼的时刻-对不起!与print()
3kstc

2
如果要索引,只需添加index=range(len(mylist))for a, b in itertools.combinations(index, 2):然后添加即可compare(mylist[a], mylist[b])。现在,您可以使用索引从中获取元素mylist
allenyllee

25

采用 itertools.combinations(mylist, 2)

mylist = range(5)
for x,y in itertools.combinations(mylist, 2):
    print x,y

0 1
0 2
0 3
0 4
1 2
1 3
1 4
2 3
2 4
3 4

2
这真的很有帮助。谢谢。
theteddyboy's

10

我认为在外循环上使用枚举并在内循环上使用索引对列表进行切片是非常Pythonic的:

for index, this in enumerate(mylist):
    for that in mylist[index+1:]:
        compare(this, that)

起初我以为“ index + 1”可能会在到达外部for循环的最终索引时导致索引越界错误,但是在Python列表切片中,如果您给出的起始位置大于或等于列表的长度,然后简单给出并清空列表
Ghos3t

1
@ Ghos3t当然是一个方便的功能。如果由于不需要跳过最后一个迭代,则将最后一个元素从要枚举的列表中切出:mylist[:-1]
alan

-1

您的解决方案是正确的,但是您的外循环仍然比所需的时间更长。您不需要将最后一个元素与其他任何元素进行比较,因为在先前的迭代中已经将它与所有其他元素进行了比较。您的内部循环仍然可以防止这种情况,但是由于我们在谈论碰撞检测,因此您可以节省不必要的检查。

使用用于说明算法的相同语言,您会得到如下所示的内容:

for (int i = 0, i < mylist.size() - 1; ++i)
    for (int j = i + 1, j < mylist.size(); --j)
        compare(mylist[i], mylist[j])

检查列表大小时,内部循环计数器向后移动。
Baris Demiray

感谢您指出这一点,当从真实代码转换为伪语言时,一定是拼写错误。不管怎么说,这是从快速同一行之有效的解决方案:github.com/diogoeichert/quick/blob/...
迪奥戈Eichert

-2

此代码将计算频率并删除重复的元素:

from collections import Counter

str1='the cat sat on the hat hat'

int_list=str1.split();

unique_list = []
for el in int_list:

    if el not in unique_list:
        unique_list.append(el)
    else:
        print "Element already in the list"

print unique_list

c=Counter(int_list)

c.values()

c.keys()

print c
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.