Move two lists of different lengths in python v. 2?

I am trying to write a Python function that takes two lists as arguments and interleaves them. The order of the component lists must be maintained. If lists do not have the same length, the elements of a longer list should end at the end of the resulting list. For example, I would like to put this in a Shell:

interleave(["a", "b"], [1, 2, 3, 4]) 

And return this:

 ["a", 1, "b", 2, 3, 4] 

If you help me, I will be grateful.

+4
source share
4 answers

Here's how I would do it using the various bits of the itertools module. It works for any number of iterations, not just two:

 from itertools import chain, izip_longest # or zip_longest in Python 3 def interleave(*iterables): sentinel = object() z = izip_longest(*iterables, fillvalue = sentinel) c = chain.from_iterable(z) f = filter(lambda x: x is not sentinel, c) return list(f) 
+1
source

You can try the following:

 In [30]: from itertools import izip_longest In [31]: l = ['a', 'b'] In [32]: l2 = [1, 2, 3, 4] In [33]: [item for slist in izip_longest(l, l2) for item in slist if item is not None] Out[33]: ['a', 1, 'b', 2, 3, 4] 

izip_longest "zips" combines the two lists, but instead of stopping in the shortest list, it continues until the longest is exhausted:

 In [36]: list(izip_longest(l, l2)) Out[36]: [('a', 1), ('b', 2), (None, 3), (None, 4)] 

Then you add items by iterating over each item in each pair in the encrypted list, omitting those that are None . As pointed out by @Blckknight, this will not work properly if the source lists already have None values. If possible in your situation, you can use the fillvalue izip_longest property to fill with something other than None (as @Blckknight does in his answer).

Here is the above example as a function:

 In [37]: def interleave(*iterables): ....: return [item for slist in izip_longest(*iterables) for item in slist if item is not None] ....: In [38]: interleave(l, l2) Out[38]: ['a', 1, 'b', 2, 3, 4] In [39]: interleave(l, l2, [44, 56, 77]) Out[39]: ['a', 1, 44, 'b', 2, 56, 3, 77, 4] 
+1
source

Not a very elegant solution, but may still be useful

 def interleave(lista, listb): (tempa, tempb) = ([i for i in reversed(lista)], [i for i in reversed(listb)]) result = [] while tempa or tempb: if tempa: result.append(tempa.pop()) if tempb: result.append(tempb.pop()) return result 

or in one line

  def interleave2(lista, listb): return reduce(lambda x,y : x + y, map(lambda x: x[0] + x[1], [(lista[i:i+1], listb[i:i+1]) for i in xrange(max(len(lista),len(listb)))])) 
0
source

Another solution is based on: How do I do this manually? Well, almost manually, using the built-in zip() and extending the result of fastening the length of the shorter list with the tail of the longer:

 #!python2 def interleave(lst1, lst2): minlen = min(len(lst1), len(lst2)) # find the length of the shorter tail = lst1[minlen:] + lst2[minlen:] # get the tail result = [] for t in zip(lst1, lst2): # use a standard zip result.extend(t) # expand tuple to two items return result + tail # result of zip() plus the tail print interleave(["a", "b"], [1, 2, 3, 4]) print interleave([1, 2, 3, 4], ["a", "b"]) print interleave(["a", None, "b"], [1, 2, 3, None, 4]) 

He prints the results:

 ['a', 1, 'b', 2, 3, 4] [1, 'a', 2, 'b', 3, 4] ['a', 1, None, 2, 'b', 3, None, 4] 
0
source

Source: https://habr.com/ru/post/1444029/


All Articles