比较两个列表并找出变化的索引

10

我正在尝试比较两个列表,并找到该位置上的变化字符和其位置。例如,这是两个列表:

list1 = ['I', 'C', 'A', 'N', 'R', 'U', 'N']
list2 = ['I', 'K', 'A', 'N', 'R', 'U', 'T']

我希望能够输出两个列表中的差异位置和变化。正如您所看到的,一个字母可以在不同的索引位置上重复多次。这是我尝试过的代码,但我似乎无法准确地打印出第二个位置。

for indexing in range(0, len(list1)):
    if list1[indexing] != list2[indexing]:
        dontuseindex = indexing
        poschange = indexing + 1
        changecharacter = list2[indexing]
for indexingagain in range(dontuseindex + 1, len(list1)):
    if list1[indexingagain] != list2[indexingagain]:
        secondposchange = indexingagain + 1
        secondchangecharacter = list2[indexingagain]

有没有更好的解决方法或对我现有代码的任何建议?

我的期望输出应该是:

2    K
7    T

你只关心替换还是也包括插入/删除呢?如果是前者:只需使用zip并比较即可;如果是后者,则需要使用Levenshtein distance的变体。 - tobias_k
@PeterWood已经列出了我期望的输出。 - interstellar
@tobias_k 我只关心替换。列表的长度将始终相同。 - interstellar
显然,[print(ix, *thing) for ix, thing in enumerate(map(set, zip(list1, list2))) if len(thing) == 2] 是唯一好的方法。 - DaveBensonPhillips
仅备注,索引为 16 - Peter Wood
3个回答

16
for index, (first, second) in enumerate(zip(list1, list2)):
    if first != second:
        print(index, second)

输出:

1 K
6 T

如果你想得到你所提供的输出,我们需要从1开始计数,而不是通常的0

for index, (first, second) in enumerate(zip(list1, list2), start=1):

我认为这应该很好地工作,我应该能够轻松实现它。谢谢! - interstellar
有没有一种简单的方法将更改和索引存储到两个不同的变量中?例如,position1position2change1change2 - interstellar
如果有三个更改怎么办?也许你应该再考虑一下,搜索后将其作为一个单独的问题提出。 - Peter Wood
请注意,OP的索引从1开始,因此可能需要使用enumerate(zip(list1, list2), start=1) - tobias_k
@tobias_k 我必须承认,我不确定原始示例在做什么。 - Peter Wood

4

使用列表推导式可以将所有不相等的元素与索引保存在一起:

list1 = ['I', 'C', 'A', 'N', 'R', 'U', 'N']
list2 = ['I', 'K', 'A', 'N', 'R', 'U', 'T']

# Append index, element1 and element2 as tuple to the list if they are not equal
changes = [(i, list1[i], list2[i]) for i in range(len(list1)) if list1[i] != list2[i]]
print(changes)
#prints [(1, 'C', 'K'), (6, 'N', 'T')]

虽然不是完全符合您指定的输出结果,但它非常接近。

您可以使用循环打印出指定的输出:

for i in changes:
    print(i[0] + 1, i[1])
# 2 K
# 7 T

在评论中,提出了几种设计列表推导式的替代方法:
  • Using enumerate and zip:

    changes = [(i, e1, e2) for i, (e1, e2) in enumerate(zip(list1, list2)) if e1 != e2]
    
  • Using enumerate with start index and zip:

    changes = [(i, e1, e2) for i, (e1, e2) in enumerate(zip(list1, list2), 1)  if e1 != e2]
    
  • Using zip and itertools.count:

    import itertools
    changes = [(i, e1, e2) for i, e1, e2 in zip(itertools.count(), list1, list2)) if e1 != e2]
    
  • Using zip and itertools.count with start-index:

    changes = [(i, e1, e2) for i, e1, e2 in zip(itertools.count(1), list1, list2)) if e1 != e2]
    

所有这些都会产生与原始结果相同的结果,但是使用不同(更好的)Python功能。


2
为什么不使用 zipenumerate - Peter Wood
1
@PeterWood 你提出了一个有趣的问题:如果两个列表长度不同,那算不算差异?我知道在这种情况下zipenumerate是更好的选择,只是提供了一种替代方案,因为你已经提供了那种Pythonic的迭代方式。我想我会把它作为答案中的替代方案。我没有感到任何同行压力,这只是对你第一条评论上的两个赞的评论而已。 :-) - MSeifert
1
我在想,zip(count(), list1, list2) 会更加统一,因为不需要奇怪的元组解包语法。使用 itertools.count - Peter Wood
1
enumerate 允许设置 start 索引。不需要 count,这正是 enumerate 的作用! - tobias_k
1
我也包含了这个。从来没有意识到它有这个参数。谢谢! - MSeifert
显示剩余5条评论

0
list1 = ['I', 'C', 'A', 'N', 'R', 'U', 'N']
list2 = ['I', 'K', 'A', 'N', 'R', 'U', 'T']
[i for i, x in enumerate(zip(list1,list2)) if x[0]!=x[1]]

输出:

[1, 6]

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