blueFast
blueFast

Reputation: 44351

List comprehension with several elements per entry

This one is clear:

a = ['a', 'b', 'c']
x = [v for v in a]

But I am not sure how to do this:

sep = 5
# ??? y = [v + sep for v in a]
print y # expected ['a', 5, 'b', 5, 'c', 5]

How can I write a list comprehension with multiple elements per source element?

I am not interested in optimizations of this code: please do not refer to the [:] operator or join method or something on those lines. My code needs a list comprehension. The only alternative I have at the moment is a 4 lines for loop, which is inconvenient:

y = []
for v in a:
    y.append(v)
    y.append(sep)

Upvotes: 3

Views: 190

Answers (6)

dansalmo
dansalmo

Reputation: 11686

>>> a = ['a', 'b', 'c']
>>> [item for sublist in zip(a, [5]*len(a)) for item in sublist]
['a', 5, 'b', 5, 'c', 5]

To break it down:

>>> [5]*len(a)
[5, 5, 5]

>>> zip(a, [5]*len(a))
[('a', 5), ('b', 5), ('c', 5)]

The list of tuples is then flattened using the following idiom:

[item for sublist in l for item in sublist]

Using timeit, this approach was 15% faster than the fastest itertools method

>>> stmt3 = """
[item for sublist in zip(a, [5]*len(a)) for item in sublist]
"""
>>> timeit.timeit(stmt=stmt3, setup="a = ['a', 'b', 'c']", number=100000)

Upvotes: 0

Abhijit
Abhijit

Reputation: 63717

This is a perfect problem to show how powerful Python's itertool package is

repeat: Creates an endless (or upto a limit) iterable of an object

izip: Transposes the iterables.

chain Unwraps an iterable

>>> from itertools import izip, chain, repeat
>>> a = ['a', 'b', 'c']
>>> list(chain.from_iterable(izip(a, repeat(5))))
['a', 5, 'b', 5, 'c', 5]

And if you have a knack for micro optimization, you may be interested to know, this is faster than list comprehension

>>> stmt1 = """
list(chain.from_iterable((elem, 5) for elem in a))
"""
>>> stmt2 = """
list(chain.from_iterable(izip(a, repeat(5))))
"""
>>> timeit.timeit(stmt=stmt1, setup="from __main__ import chain, a", number=100000)
1.3136643729533688
>>> timeit.timeit(stmt=stmt2, setup="from __main__ import chain, izip, repeat, a", number=100000)
0.8959859753707633
>>> 

Upvotes: 1

Rohit Jain
Rohit Jain

Reputation: 213223

You can build a list of tuples first, and then flatten the resulting list using itertools.chain.from_iterable:

>>> sep = 5
>>> a = ['a', 'b', 'c']
>>> 
>>> import itertools
>>> list(itertools.chain.from_iterable((elem, sep) for elem in a))
['a', 5, 'b', 5, 'c', 5]

Upvotes: 5

Deelaka
Deelaka

Reputation: 13693

Simply use the function sum() to flatten the list of list as [[v,sep] for v in a] will produce [['a', 5], ['b', 5], ['c', 5]]

a = ['a', 'b', 'c']
x = [v for v in a]
sep = 5
y = sum([[v,sep] for v in a],[])
print y
#['a', 5, 'b', 5, 'c', 5]

Upvotes: 1

falsetru
falsetru

Reputation: 369024

Using nested list comprehension:

>>> a = ['a','b','c']
>>> [item  for x in a for item in (x, 5)]
['a', 5, 'b', 5, 'c', 5]

Upvotes: 6

YXD
YXD

Reputation: 32511

result = [5 if i % 2 else a[i/2] for i in range(2*len(a))]

(Not that you should put code like this into production)

Upvotes: 0

Related Questions