[Tutor] Better way to insert items into a list

Steven D'Aprano steve at pearwood.info
Sun Dec 9 01:18:37 CET 2012


On 09/12/12 06:39, Mike wrote:
> Hello everyone,
>
> I was wondering if someone could show me a better way to achieve what
> I am trying to do.  Here is my test code:
>
>      d=[]
>      c="00"
>      a="A,B,C,D"
>      b=a.split(',')
>      for item in b:
>          d.append(item)
>          d.append(c)
>      print tuple(d)
>
> Basically what I want to end up with is a tuple that looks like this:
> ("A","00","B","00","C","00")...

I'm not so sure about a "better way" -- the way you have works, it is
pretty simple and obvious. I might argue about the one-letter names.


> As you can see I want to insert 00 in-between each element in the
> list.  I believe this could be done using a list comprehension?

Not really. List comprehensions don't solve every list problem.


> I realize I achieved my goal, but I was wondering what other
> alternates could be done to achieve the same results.

Here are a couple of alternatives:


result = []
insert = "00"
items = "A,B,C,D".split(',')
for a, b in zip(items, [insert]*len(items)):
     result.append(a)
     result.append(b)
print tuple(result)

# === cut ===

from itertools import repeat
result = []
insert = repeat("00")
items = "A,B,C,D".split(',')
for a, b in zip(items, insert):
     result.append(a)
     result.append(b)
print tuple(result)



Here is a more heavyweight solution to interleave any number of sequences.
I make no promise that this is the most efficient way to write this:


from itertools import izip_longest
def interleave(*args):
     """Interleave sequences into one list.

     With equal-length sequences, the items are taken alternatively from one
     to the other:

     >>> interleave([1, 2, 3, 4, 5], [0, 0, 0, 0, 0])
     [1, 0, 2, 0, 3, 0, 4, 0, 5, 0]

     More than two sequences can be interleaved, of different types:

     >>> interleave([1, 2, 3], (0, 0, 0), iter('abc'))
     [1, 0, 'a', 2, 0, 'b', 3, 0, 'c']

     If the sequences are of different lengths, they alternate as long as
     possible, then the items from the longer sequence are included:

     >>> interleave([1, 2, 3, 4, 5], [0, 0, 0])
     [1, 0, 2, 0, 3, 0, 4, 5]
     >>> interleave([1, 2, 3], [0, 0, 0, 0, 0])
     [1, 0, 2, 0, 3, 0, 0, 0]

     """
     sentinel = object()
     result = []
     for t in izip_longest(*args, fillvalue=sentinel):
         result.extend([x for x in t if x is not sentinel])
     return result


items = "A,B,C,D".split(',')
print interleave(items, ["00"]*len(items))


Another name for interleaving is muxing, from "multiplexing" in signal
processing:


from itertools import izip_longest
def longmux(*iterables, **kwargs):
     """longmux(*iterables, [fillvalue=None]) -> iterator

     Muxer which yields items interleaved from each iterator or
     sequence argument, stopping when all of them are exhausted.
     Missing values are replaced by optional keyword argument
     fillvalue, or None if not given.

     >>> list( longmux([1,2,3], xrange(10, 15), "ABCD") )
     [1, 10, 'A', 2, 11, 'B', 3, 12, 'C', None, 13, 'D', None, 14, None]
     >>> list( longmux([1,2,3], xrange(10, 15), "ABCD", fillvalue=-1) )
     [1, 10, 'A', 2, 11, 'B', 3, 12, 'C', -1, 13, 'D', -1, 14, -1]
     """
     # This is much easier in Python 3.
     if kwargs == {}:
         fillvalue = None
     elif kwargs.keys() != ['fillvalue']:
         raise TypeError('bad keyword argument')
     else:
         fillvalue = kwargs['fillvalue']
     for i in izip_longest(*iterables, fillvalue=fillvalue):
         for item in i:
             yield item


print tuple(longmux("A,B,C,D".split(","), [], fillvalue="00"))




-- 
Steven


More information about the Tutor mailing list