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

时间:2013-05-17 07:02:12

标签: python

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

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解决方案是什么?

5 个答案:

答案 0 :(得分:92)

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

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

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

itertools.combinations会将每个元素与iterable中的每个其他元素配对,但只会一次。


你仍然可以使用基于索引的项目访问来编写它,相当于你习惯使用嵌套的for循环:

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

当然,这可能看起来并不像pythonic那样好,但有时候这仍然是最容易理解的解决方案,所以你不应该回避解决这类问题。

答案 1 :(得分:21)

使用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 :(得分:4)

我认为在外部循环上使用enumerate并使用索引来切割内部循环上的列表非常Pythonic:

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

答案 3 :(得分:-1)

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

使用与用于说明算法的语言相同的语言,您会得到以下类似信息:

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

答案 4 :(得分:-3)

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

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