Python迭代两个列表并比较它们的元素

8
我有两个列表,例如x = [1,2,3,4,4,5,6,7,7] y = [3,4,5,6,7,8,9,10],我想在迭代这两个列表时进行比较。对于匹配的条目,我想调用一些函数并从列表中删除它们。在这个例子中,我最终应该得到x = [1,2]和y = [8,9,10]。由于我的数据类型和比较运算符的原因,集合不适用于此问题。
for i in x:
  for j in y:
    if i ==j:
       callsomefunction(i,j)
       remove i, j from x and y respectively

你的示例是按排序顺序排列的。你的实际数据是否也是按排序顺序排列的? - Mike Graham
2
数据可排序吗?为什么你的数据不可哈希?xy有多大? - Mike Graham
1
你提到不能使用set()是因为你的比较运算符,我很好奇它是什么。另外,那会阻止你使用内部循环而改用if i in y吗? - Shawn Chin
2
无论找到多少次ij,组合callsomefunction(i, j)是否应该仅被调用一次?如果不是,那么规则是什么? - Mike Graham
4个回答

4

编辑:在发现提问者不知道__hash__的情况下,我在评论中提供了以下信息:

要使用集合,请实现__hash__。如果obj1.a == obj2.a and ob1.b == obj2.bobj1 == obj2,则__hash__应为return hash((self.a, self.b)),这样您的集合将按预期工作。

这解决了他们的问题,他们转而使用集合。

本答案的其余部分现已过时,但仍然正确(但效率极低),因此我将其保留在此处。


此代码可以实现您想要的功能。最终,newxnewy是特定于xy的非重叠项。

x = [1,2,3,4,4,5,6,7,7]
y = [3,4,5,6,7,8,9,10]
# you can leave out bad and just compare against
# x at the end if memory is more important than speed
newx, bad, newy = [], [], []
for i in x:
    if i in y:
        callsomefunction(i)
        bad.append(i)
    else:
        newx.append(i)

for i in y:
    if i not in bad:
        newy.append(i)

print newx
print newy

然而,即使我没有看到你的代码,我也知道这不是正确的方法。你可以用集合来实现,但如果你不想用,那就由你决定。


集合的问题在于我的数据集(对象),因此比较操作被定义为比较对象的特定属性。让我使用这个解决方案。谢谢。 - user739807
1
@user739807,你是指“I defined __cmp__ but not __hash__”吗?如果是这样,你可能想要定义__hash__。那可以将这个二次方代码转换为线性代码。(另外,如果你正在定义__cmp__,那么你可能想要定义__eq__)。 - Mike Graham

3

好的, 抛弃我的帖子,我没有看到你提到集合不起作用的点。

然而,如果你愿意付出一点努力,你可能想使用类来使运算符按照预期工作。

我认为最"pythonic"的方法是使用集合。 然后,你可以这样做:

x = set([1,2,3,4,4,5,6,7,7])
y = set([3,4,5,6,7,8,9,10])
for item in x.intersection(y): #y.intersection(x) is fine too.
    my_function(item) #You could use my_function(item, item) if that's what your function requires
    x.remove(item)
    y.remove(item)

我认为对于这种需要高性能的工作,相比列表,集合更加高效(尽管这可能不是您的首要考虑因素)。

顺带一提,您也可以使用:

x,y = x.difference(y), y.difference(x) 

这将有效地从x和y中移除在x和y中存在的项目。

他现在正在使用集合,只是他之前不知道 __hash__,所以他认为它对他的对象无效。 - agf

1

试一下:

for i in x:
    if i in y:
        callsomefunction(i)
        x.remove(i)
        y.remove(i)

编辑:更新答案


zip不起作用,因为两个列表的长度不同。而且我们还有重复项。 - user739807
1
你运行了这段代码吗?它并没有产生 OP 所要求的输出。 - Lauritz V. Thaulow
zip() 对 OP 使用的嵌套循环产生了不同的结果。如果不考虑 remove(..) 的要求,itertools.product() 更加合适。 - Shawn Chin
这实际上是有效的,但当x或y具有重复项时,它只会删除一个出现。 - user739807

-1
这样怎么样:
import itertools
x = [1,2,3,4,4,5,6,7,7] 
y = [3,4,5,6,7,8,9,10]
output = map(somefunction, itertools.product(x,y))

itertools.product() 可以给出正确的迭代顺序,但是一旦您开始在迭代过程中删除列表中的条目,事情可能会变得棘手。 - Shawn Chin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接