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

Time:03-03

I have three lists: vals1, vals2, and names. names includes only strings and the other two lists (vals1, vals2) contain numbers only. The lengths of the three lists are always the same. My goal is to write a function that compares vals1and vals2 and return a message or a list depending on the result of the comparison. If vals1and vals2 are equal, then the function returns a message that states the two lists are equal. List comparison must be done in the preserved order. For example, vals1 = [1,2,3,2] is not equal to vals2 = [1,2,2,3]. If the two numeric lists (vals1and vals2) are not equal, the function will return a list that contains tuples. Each tuple in this list contains the index of one element in vals1 and vals2 that are not equal, the corresponding element in the string list names, and the corresponding element in vals1. This is the function that I wrote for this task:

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]])

For

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

compareLists will return

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

The function works, but I wanted to know if there is a more efficient way (a more pythonic approach) to this. Any help would be appreciated.

CodePudding user response:

There's nothing wrong with your method, imo.

Alternatively, you could use 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'

If you have Python >=3.8, you can also write the above in one line (a lot less readable though):

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

Output:

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

We could also write a genexp (thanks @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)

CodePudding user response:

I'd suggest using enumerate() as opposed to using range(). You can also remove the else in the function, as it's redundant:

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))
  • Related