# What is the best way to interleave two lists?

• A+
Category：Languages

Suppose I have a list:

``l=['a','b','c'] ``

I'd like the desired output to be:

``out_l = ['a','a_1','b','b_2','c','c_3'] ``

I can write regular `for` loop to get this done, but I'm wondering if there's a more Pythonic way (e.g., using list comprehension or lambda) to get it done.

I've tried something like this:

``list(map(lambda x: x+'_'+str(x+1), enumerate(a))) # this only returns ['a_1', 'b_2', 'c_3'] ``

# `yield`

You can use a generator for an elegant solution. At each iteration, yield twice—once with the original element, and once with the element with the added suffix.

The generator will need to be exhausted; that can be done by tacking on a `list` call at the end.

``def transform(l):     for i, x in enumerate(l, 1):         yield x         yield f'{x}_{i}'  # {}_{}'.format(x, i) ``

You can also re-write this using the `yield from` syntax for generator delegation:

``def transform(l):     for i, x in enumerate(l, 1):         yield from (x, f'{x}_{i}') # (x, {}_{}'.format(x, i)) ``

``out_l = list(transform(l)) print(out_l) ['a', 'a_1', 'b', 'b_2', 'c', 'c_3'] ``

If you're on versions older than python-3.6, replace `f'{x}_{i}'` with `'{}_{}'.format(x, i)`.

# Sliced `list.__setitem__`

I'd recommend this from the perspective of performance. First allocate space for an empty list, and then assign list items to their appropriate positions using sliced list assignment. `l` goes into even indexes, and `l'` (`l` modified) goes into odd indexes.

``out_l = [None] * (len(l) * 2) out_l[::2] = l out_l[1::2] = [f'{x}_{i}' for i, x in enumerate(l, 1)]  # [{}_{}'.format(x, i) ...] ``

``print(out_l) ['a', 'a_1', 'b', 'b_2', 'c', 'c_3'] ``

This is consistently the fastest from my timings (below).

# `zip` + `chain.from_iterable`

A functional approach, similar to @chrisz' solution. Construct pairs using `zip` and then flatten it using `itertools.chain`.

``from itertools import chain # [{}_{}'.format(x, i) ...] out_l = list(chain.from_iterable(zip(l, [f'{x}_{i}' for i, x in enumerate(l, 1)])))  ``

``print(out_l) ['a', 'a_1', 'b', 'b_2', 'c', 'c_3'] ``

`iterools.chain` is widely regarded as the pythonic list flattening approach.

Performance
Let's take a look at some perf-tests.

``from timeit import timeit  import pandas as pd import matplotlib.pyplot as plt  res = pd.DataFrame(        index=['ajax1234', 'cs0', 'cs1', 'cs2', 'cs3', 'chrisz', 'sruthiV'],        columns=[10, 50, 100, 500, 1000, 5000, 10000, 50000, 100000],        dtype=float )  for f in res.index:      for c in res.columns:         l = ['a', 'b', 'c', 'd'] * c         stmt = '{}(l)'.format(f)         setp = 'from __main__ import l, {}'.format(f)         res.at[f, c] = timeit(stmt, setp, number=50)  ax = res.div(res.min()).T.plot(loglog=True)  ax.set_xlabel("N");  ax.set_ylabel("time (relative)");  plt.show() `` Functions

``def ajax1234(l):     return [         i for b in [[a, '{}_{}'.format(a, i)]          for i, a in enumerate(l, start=1)]          for i in b     ]  def cs0(l):     # this is in Ajax1234's answer, but it is my suggestion     return [j for i, a in enumerate(l, 1) for j in [a, '{}_{}'.format(a, i)]]  def cs1(l):     def _cs1(l):         for i, x in enumerate(l, 1):             yield x             yield f'{x}_{i}'      return list(_cs1(l))  def cs2(l):     out_l = [None] * (len(l) * 2)     out_l[::2] = l     out_l[1::2] = [f'{x}_{i}' for i, x in enumerate(l, 1)]      return out_l  def cs3(l):     return list(chain.from_iterable(         zip(l, [f'{x}_{i}' for i, x in enumerate(l, 1)]))     )  def chrisz(l):     return [         val          for pair in zip(l, [f'{k}_{j+1}' for j, k in enumerate(l)])          for val in pair     ]  def sruthiV(l):     return [          l[int(i / 2)] + "_" + str(int(i / 2) + 1) if i % 2 != 0 else l[int(i/2)]          for i in range(0,2*len(l))     ] ``

Software
System—Mac OS X High Sierra—2.4 GHz Intel Core i7
Python—3.6.0
IPython—6.2.1