通过两个其他列表的保留顺序比较返回一个列表元素的 Pythonic 方法

Pythonic way for returning elements of one list by an order-preserved comparation of two other lists

我有三个列表:vals1vals2namesnames 仅包含字符串,而其他两个列表(vals1vals2)仅包含数字。三个列表的长度总是相同的。我的目标是编写一个函数,根据比较结果比较 vals1vals2 和 return 消息或列表。如果 vals1vals2 相等,则函数 return 是一条消息,表明两个列表相等。列表比较必须以保留的顺序进行。例如,vals1 = [1,2,3,2] 不等于 vals2 = [1,2,2,3]。如果两个数字列表(vals1vals2)不相等,函数将 return 一个包含元组的列表。此列表中的每个元组包含 vals1vals2 中不相等的一个元素的索引,字符串列表中对应的元素 names,以及 [=13= 中的对应元素].这是我为此任务编写的函数:

def compareLists(l1, l2, names):
    if l1==l2:
        return "Equal"
    else:
        return ([(item, idx, val) for (item, idx, val) in 
               zip(names, range(len(names)), l1) if l1[idx]!=l2[idx]])

为了

vals1=[12, 2, 2, 7, 5]
vals2=[12, 5, 2, 7, 15]
names=['a','b','c','d','e']

compareLists 将 return

[('b', 1, 2), ('e', 4, 5)]

该函数有效,但我想知道是否有更有效的方法(更 pythonic 的方法)。任何帮助将不胜感激。

我觉得你的方法没有问题。

或者,您可以使用 zip + enumerate:

out = [(n, idx, i) for idx, (i, j, n) in enumerate(zip(vals1, vals2, names)) if i!=j]
out = out if out else 'equal'

如果你有Python >=3.8,你也可以把上面的写成一行(虽然可读性差很多):

out = out if (out:= [(n, idx, i) for idx, (i, j, n) in enumerate(zip(vals1, vals2, names)) if i!=j]) else 'equal'

输出:

[('b', 1, 2), ('e', 4, 5)]

我们也可以写一个 genexp(感谢@JonClements):

t = ((n, idx, i) for idx, (i, j, n) in enumerate(zip(vals1, vals2, names)) if i!=j)
out = 'equal' if vals1 == vals2 else list(t)

我建议使用 enumerate() 而不是 range()。您还可以删除函数中的 else,因为它是多余的:

def compareLists(l1, l2, names):
    if l1 == l2:
        return "Equal"
    return ([(item, idx, val) for idx, (item, val) in 
               enumerate(zip(names, l1)) if l1[idx] != l2[idx]])

vals1=[12, 2, 2, 7, 5]
vals2=[12, 5, 2, 7, 15]
names=['a','b','c','d','e']
print(compareLists(vals1, vals2, names))