Pythonic way to mix two lists

I have two lists of length n and n + 1:

[a_1, a_2, ..., a_n] [b_1, b_2, ..., b_(n+1)] 

I need a function that results in a list with alternative elements of two, i.e.

 [b_1, a_1, ..., b_n, a_n, b_(n+1)] 

The following actions, but do not look smart:

 def list_mixing(list_long,list_short): list_res = [] for i in range(len(list_short)): list_res.extend([list_long[i], list_short[i]]) list_res.append(list_long[-1]) return list_res 

Can anyone suggest a more pythonic way to do this? Thank!

+9
python
Sep 23 2018-11-11T00:
source share
10 answers

IMHO the best way:

 result = [item for sublist in zip(a,b) for item in sublist] 

It is also faster than the amount and reduces opportunities.

UPD I'm sorry that your second list is one more item :) There is another crazy way:

 result = [item for sublist in map(None, a, b) for item in sublist][:-1] 
+12
Sep 23 '11 at 13:15
source share
 >>> import itertools >>> a ['1', '2', '3', '4', '5', '6'] >>> b ['a', 'b', 'c', 'd', 'e', 'f'] >>> list(itertools.chain.from_iterable(zip(a,b))) ['1', 'a', '2', 'b', '3', 'c', '4', 'd', '5', 'e', '6', 'f'] 

zip() creates an iteration with the length of the shortest argument. You can either add a[-1] to the result, or use itertools.zip_longest (izip_longest for Python 2.x) with a fill value and subsequently delete that value.

And you can use more than two input sequences with this solution.

In order not to add the last value, you can try this dirty approach, but I really do not recommend it, it is not clear:

 >>> a [1, 2, 3, 4, 5] >>> b ['a', 'b', 'c', 'd', 'e', 'f'] >>> [a[i//2] if i%2 else b[i//2] for i in range(len(a)*2+1)] ['a', 1, 'b', 2, 'c', 3, 'd', 4, 'e', 5, 'f'] 

(For Python 2.x use single / )

+16
Sep 23 2018-11-11T00:
source share
 >>> long = [1, 3, 5, 7] >>> short = [2, 4, 6] >>> mixed = [] >>> for i in range(len(long)): >>> mixed.append(long[i]) >>> if i < len(short) >>> mixed.append(short[i]) >>> mixed [1, 2, 3, 4, 5, 6, 7] 
+4
Sep 23 '11 at 13:13
source share

Mixing two lists is the job for zip :

 res = [] for a,b in zip(list_long, list_short): res += [a,b] 

for lists of different lengths, define your own function:

 def mix(list_long, list_short): result = [] i,j = iter(list_long), iter(list_short) for a,b in zip(i,j): res += [a,b] for rest in i: result += rest for rest in j: result += rest return result 

using the answer given by Mihail , we can shorten this:

 def mix(list_long, list_short): i,j = iter(list_long), iter(list_short) result = [item for sublist in zip(i,j) for item in sublist] result += [item for item in i] result += [item for item in j] return result 
+3
Sep 23 2018-11-11T00:
source share

I would use a combination of the above answers:

 >>> a = ['1', '2', '3', '4', '5', '6'] >>> b = ['a', 'b', 'c', 'd', 'e', 'f', 'g'] >>> [i for l in izip_longest(a, b, fillvalue=object) for i in l if i is not object] <<< ['1', 'a', '2', 'b', '3', 'c', '4', 'd', '5', 'e', '6', 'f', 'g'] 
+2
Sep 23 '11 at 13:38
source share
 sum([[x,y] for x,y in zip(b,a)],[])+[b[-1]] 

Note. This only works for your given list lengths, but can easily be extended to arbitrary length lists.

+1
Sep 23 '11 at 13:09
source share

Use izip_longest to fill in the blanks with what you don’t have on your lists, or don’t want to save the result. If you do not want to allow anything to be False , use the default values ​​for izip_longest and filter :

 from itertools import chain, izip_longest l1 = [1,3,5] l2 = [2,4,6,8,10] filter(None, chain(*izip_longest(l1,l2))) 

result: [1, 2, 3, 4, 5, 6, 8, 10]

Using None to fill in spaces and remove them with filter :

 filter(lambda x: x is not None, chain(*izip_longest(l1,l2, fillvalue=None))) 

For greater efficiency, when l1 or l2 are not short lists, but, for example, very long or endless iterations, use ifilter instead of filter , which will give you iterability instead of putting everything into memory in the list. Example:

 from itertools import chain, izip_longest, ifilter for value in ifilter(None, chain(*izip_longest(iter1,iter1))): print value 
+1
Jun 08 '14 at 12:45
source share

You can do something like the following (assuming len(list_long)==len(list_short)+1 :

 def list_mixing(list_long,list_short): return [(list_long[i/2] if i%2==0 else list_short[i/2]) for i in range(len(list_long)+len(list_short)] 

Where I use / for integer division (exactly what the operator for this depends on the language version).

0
Sep 23 2018-11-11T00:
source share

This is the best I have found:

 import itertools l1 = [1, 3, 5] l2 = [2, 4, 6, 8, 10] result = [ x # do something for x in itertools.chain.from_iterable(itertools.zip_longest(l1, l2, l1)) if x is not None ] result # [1, 2, 1, 3, 4, 3, 5, 6, 5, 8, 10] 

For zip_longest clarity, zip_longest groups elements by index:

 iter = list(itertools.zip_longest(l1, l2, l1)) iter[0] # (1, 2, 1) iter[1] # (3, 4, 3) iter[-1] # last # (None, 10, None) 

After that, itertools.chain.from_iterable aligns them in order.

Reasons why he is the best:

  • None filtering is no longer recommended, use list comprehension
  • List comprehension also allows you to immediately "do something" with x
  • it doesn't throw items if some lists are longer than the shortest
  • works with any number of lists
  • in fact, it’s very easy to talk about what happens contrary to all the “intelligence” there
0
Feb 02 '19 at 10:51
source share

Use zip. This will give you a list of tuples, for example: [('a_1', 'b_1'), ('a_2', 'b_2'), ('a_3', 'b_3')]

If you want to clear it to a pretty list, just go through the list of tuples with the listing:

 alist = ['a_1', 'a_2', 'a_3'] blist = ['b_1', 'b_2', 'b_3'] clist = [] for i, (a, b) in enumerate(zip(alist, blist)): clist.append(a) clist.append(b) print clist ['a_1', 'b_1', 'a_2', 'b_2', 'a_3', 'b_3'] 
-one
Sep 23 '11 at 13:22
source share



All Articles