在列表中查找匹配和不匹配的项

7

我在学习Python,对列表的使用有些困惑。我有两个列表,想要比较它们并返回相同和不同元素的二进制格式。

List1 长度固定,而 List2 的长度各不相同(但总是比 List1 短)。

例如:

List1 = ['dog', 'cat', 'pig', 'donkey']
List2 = ['dog', 'cat', 'donkey']

期望输出:

List3 = [1, 1, 0, 1]

我目前所拥有的代码是:
def match_nonmatch(List1, List2):
    List3 = []
    for i in range(len(List1)):
        for j in range(len(List2)):
            if List1[i] == List2[j]:
                List3.append(1)
            else:
                List3.append(0)
   return List3

我可以比较列表并返回匹配项,但是当我包含上面显示的else语句来返回不匹配项时,结果列表比应该有的要长得多。例如,当我使用一个包含60个项目的列表进行比较时,我得到的列表包含3600个项目而不是60个。
如果有人能解释一下我目前代码的问题,并建议我如何修改代码以实现我的目标,我将不胜感激。
6个回答

22

使用set替代list。这样你可以做很多好玩的事情:

set1 = set(['dog', 'cat', 'pig', 'donkey'])
set2 = set(['dog', 'cat', 'donkey'])

matched = set1.intersection(set2) # set(['dog', 'cat', 'donkey'])
unmatched = set1.symmetric_difference(set2) # set(['pig'])

我知道这不完全是你所要求的,但在做这种事情时,使用集合通常比列表更好。

有关集合的更多信息,请参阅此处:http://docs.python.org/library/stdtypes.html#set


谢谢提供集合的链接。之前没有接触过这个概念,我会去了解一下。 - Platypus

10
请使用以下代码。
listt3=[]

for i in listt1:
    if i in listt2:
        listt3.append(1)
    else:
        listt3.append(0)

如果你更喜欢单行代码,可以使用以下代码: listt3=[ 1 if i in listt2 else 0 for i in listt1]

@Srinivas和Platypus:你们不觉得这样做不能得到所需的精确输出吗? listt1和listt2应该交换位置以获得精确的输出。 - Sandip Agarwal
@Srinivas 随时欢迎……这段代码可以更好地转换为一行 listt3=[int(i in listt2) for i in listt1] - Sandip Agarwal
是的,同意,但是 OP 是 Python 新手。 :) - Srinivas Reddy Thatiparthy
@SandipAgarwal 更好的写法是 listt3=[ 1 if i in listt2 else 0 for i in listt1]....现在满意了吗? :) - Srinivas Reddy Thatiparthy
@Srinivas 嘿,这真的好多了。我甚至没有想到。谢谢。 :D - Sandip Agarwal

5
你也可以使用位运算符:
List1 = ['dog', 'cat', 'pig', 'donkey']  
List2 = ['dog', 'cat', 'donkey']  

匹配:
set(List1) & set(List2)   

不匹配:

set(List1) ^ set(List2) 

4

如果list2很短,我会这样做:

list1 = ['dog', 'cat', 'pig', 'donkey']
list2 = ['dog', 'cat', 'donkey']
list3 = [int(val in list2) for val in list1]
print(list3)

这将打印:

[1, 1, 0, 1]

如果list2很长,你可以先把它转换成set,以使代码更有效率:

list1 = ['dog', 'cat', 'pig', 'donkey']
set2 = set(['dog', 'cat', 'donkey'])
list3 = [int(val in set2) for val in list1]
print(list3)

你的当前代码会生成过多的元素,原因是你在内部循环的每次迭代中调用了append(),而且有 len(List1) * len(List2) 这么多次迭代。
以下是如何解决这个问题的方法:
def match_nonmatch(List1, List2):
    List3 = []
    for i in range(len(List1)):
        for j in range(len(List2)):
            if List1[i] == List2[j]:
                List3.append(1)
                break             # fix #1
        else:                     # fix #2
            List3.append(0)
    return List3

请注意添加的 break 以及现在的 else 子句是指内部的 for 而不是 if
话虽如此,我仍然会使用我答案中的一行代码。

谢谢解释。在阅读了您和其他人的回复后,我会研究一下集合这个概念 - 我之前没有接触过它。 - Platypus
@aix 你不觉得在 else 语句的那一行会引发一个错误吗? - Sandip Agarwal
1
@SandipAgarwal:不,我没有。我在发布代码之前进行了测试并且它可行。for...else是 Python 中的有效结构 - 去查一下吧。 - NPE
@aix 嘿,它可以工作了。问题出在我这边。你不觉得写成一行更好吗? - Sandip Agarwal
1
@SandipAgarwal:我有。请看我的回答的最后一句话。 - NPE

0
[int(i==j) for i, j in zip(list1, list2)]

4
欢迎来到Stack Overflow!感谢您提供这段代码片段,它可能会提供一些有限的、即时的帮助。通过展示为什么这是一个好的解决方案,一个适当的解释将极大地提高其长期价值,并使得它对于未来遇到类似问题的读者更加有用。请[编辑]您的答案并添加一些解释,包括您所做的假设。 - Machavity

0
>>> list1 = ['dog', 'cat', 'pig', 'donkey']; list2 = ['dog', 'cat', 'donkey']
>>> [i in list2 for i in list1]
[True, True, False, True]

此外,你应该阅读 PEP8,CamelCase 命名通常仅用于类。

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