After searching around for quite a while and trying to come up with a solution on my own with list comprehensions, I feel like I’ve been completely stumped on how to solve the following problem:
Given a list:
crazy_list = [a, b]
Where:
a = [['*'], ['*', '34', '*', '*', '*', '*', '*', '*', '*'], ['*', '*', '*', '102', '*', '*', '*', '*', '*'], ['*', '*', '*', '*', '*', '170', '*', '*', '*'], ['*', '*', '*', '*', '*', '*', '*', '238', '*'], ['*']]
b = [['*'], ['*', '*', '*', '102', '*', '*', '*', '*', '*'], ['*', '*', '*', '*', '*', '170', '*', '*', '*'], ['*', '*', '*', '*', '*', '*', '*', '238', '*'], ['*', '34', '*', '*', '*', '*', '*', '*', '*'], ['*']]
How do I elegantly get a new list of lists such that:
answer = [['*'], ['*', '34', '*', '102', '*', '*', '*', '*', '*'], ['*', '*', '*', '102', '*', '170', '*', '*', '*'], ['*', '*', '*', '*', '*', '170', '*', '238', '*'], ['*', '34', '*', '*', '*', '*', '*', '238', '*'], ['*']]
and how would I generalize this kind of merging to do the same for:
[a, b, c, etc...]
(c and onwards would have the same number of elements and subelements as ‘a’ and ‘b’, but would probably have different unique values in different positions)
====================v The little that I’ve been able to do so far v=====================
I can come up with a list comprehension that does do what I want for individual lists with something like:
c = ['*', '34', '*', '*', '*', '*', '*', '*', '*']
d = ['*', '*', '*', '102', '*', '*', '*', '*', '*']
by doing:
[c[item_indx] if item != '*' else d[item_indx] for item_indx, item in enumerate(c)]
but even trying to generalize what I have so far is giving me one heck of a headache…
I’m probably approaching this problem incorrectly. Some help and/or thoughts on how to solve/better-approach this problem would be much appreciated. Also, I can’t just ditch the ‘*’s as they encode important timing information. Thanks again for your time!
First, let’s figure out how to merge a sublist from
awith a sublist fromb:We take pairs of items from the two lists, and for each pair, produce one or the other element, and make a list of the results.
To generalize that to multiple lists: well,
zipaccepts*args, so there’s no problem there – we can make tuples of items from any number of lists. But then we need to take “the non-‘*’ element, if it exists, otherwise ‘*'” from that tuple.One way to do that is to make a
setof the elements, remove'*', and use any element from the result (if non-empty), otherwise use'*'. We can get “any element” from asetwith.pop(), which will raise a KeyError if the set is empty. So we make a wrapper function and then use it:Finally, we actually have a list of lists of lists, and we want to take lists from the lists of lists, element-wise. So we apply the same
ziptrick:And if we prefer, we could fold those last two into a single nested list comprehension, but you might find it clearer this way. 🙂