If order doesn't matter:
- use set operations on each pair of nested lists. Subtracting two sets produces a new set with only the elements from the first that don't appear in the second.
- Use the
zip()
function to pair up the nested lists from your two input lists.
- If your output must consist of nested lists again, convert the result of the set operation back to a list, with
list()
- Use a list comprehension to process each pair of nested lists, creating a new list with the results.
This can be expressed as a one-liner with:
[list(set(b) - set(a)) for a, b in zip(listA, listB)]
You can drop the list(...)
call if nested sets in your output is acceptable:
[set(b) - set(a) for a, b in zip(listA, listB)]
Demo:
>>> listA = [['A', 'B', 'C', 'D', 'E'], [1, 2, 3, 4, 5], ['!', '@', '#', '$', '%']]
>>> listB = [['E', 'A', 'T', 'F', 'W'], [5, 6, 8, 2, 9], ['@', '^', '&', '#', '*']]
>>> [list(set(b) - set(a)) for a, b in zip(listA, listB)]
[['W', 'F', 'T'], [8, 9, 6], ['^', '&', '*']]
>>> [set(b) - set(a) for a, b in zip(listA, listB)] # without list(...)
[{'W', 'F', 'T'}, {8, 9, 6}, {'^', '&', '*'}]
If you change your mind and decide that order does matter for the output, then:
- Only convert each nested list in
listA
to a set, once, for faster containment testing. value in listobject
has to iterate through listobject
each time, whereas value in setobject
uses hashing to test for containment in O(1) (constant) time.
- Loop over the values in a given nested list in
listB
and test the value against the matching set from listA
, keeping only the values that don't appear in the corresponding set. Use a list comprehension for this.
- You could use
map()
to handle converting the listA
nested lists to sets as you pair up the lists. This then helps avoid creating a new set each time you test a value from the nested list from listB
.
So a one-liner that preserves input ordering is:
[[v for v in nested_b if v not in set_a] for set_a, nested_b in zip(map(set, listA), listB)]
The zip()
function pairs up the sets produced from listA
(via map(set, listA)
) and the nested lists from listB
so we can use them together each iteration of the outermost list comprehension. The nested list comprehension then filters the values for each nested list:
>>> [[v for v in nested_b if v not in set_a] for set_a, nested_b in zip(map(set, listA), listB)]
[['T', 'F', 'W'], [6, 8, 9], ['^', '&', '*']]