90

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

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

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

现在,这样做的 Python 方式是什么,因为 Python 更喜欢使用迭代器而不是循环索引?

我有以下(错误的)代码:

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

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

4

4 回答 4

165

当然,这将生成每对两次,因为每个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])

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

于 2013-05-17T07:06:33.563 回答
30

采用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
于 2013-05-17T07:05:57.730 回答
12

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

for index, this in enumerate(mylist):
    for that in mylist[index+1:]:
        compare(this, that)
于 2018-02-04T20:45:16.597 回答
-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
于 2017-02-22T02:06:15.853 回答