435,536 Members | 2,165 Online
Need help? Post your question and get tips & solutions from a community of 435,536 IT Pros & Developers. It's quick & easy.

# Producing multiple items in a list comprehension

 P: n/a Is there an easy way to get a list comprehension to produce a flat list of, say, [x,2*x] for each input argument? E.g., I'd like to do something like: [ [x,2*x] for x in range(4) ] ....and receive [ 0,0,1,2,2,4,3,6] ....but of course you really get a list of lists: [[0, 0], [1, 2], [2, 4], [3, 6]] I'm aware I can use any of the standard "flatten" bits of code to turn this back into what I want, but I was hoping there's some way to avoid the "lists of lists" generation in the first place? A slightly similar problem: If I want to "merge," say, list1=[1,2,3] with list2=[4,5,6] to obtain [1,4,2,5,3,6], is there some clever way with "zip" to do so? Thanks, ---Joel Jun 27 '08 #1
13 Replies

 P: n/a Joel Koltner wrote: Is there an easy way to get a list comprehension to produce a flat list of, say, [x,2*x] for each input argument? E.g., I'd like to do something like: [ [x,2*x] for x in range(4) ] ...and receive [ 0,0,1,2,2,4,3,6] ...but of course you really get a list of lists: [[0, 0], [1, 2], [2, 4], [3, 6]] I'm aware I can use any of the standard "flatten" bits of code to turn this back into what I want, but I was hoping there's some way to avoid the "lists of lists" generation in the first place? A slightly similar problem: If I want to "merge," say, list1=[1,2,3] with list2=[4,5,6] to obtain [1,4,2,5,3,6], is there some clever way with "zip" to do so? Thanks, ---Joel -- http://mail.python.org/mailman/listinfo/python-list For the first part: def gen(n): for i in xrange(n): yield i yield 2*i print list(gen(4)) [0, 0, 1, 2, 2, 4, 3, 6] gerard Jun 27 '08 #2

 P: n/a Joel Koltner wrote: Is there an easy way to get a list comprehension to produce a flat list of, say, [x,2*x] for each input argument? E.g., I'd like to do something like: [ [x,2*x] for x in range(4) ] ...and receive [ 0,0,1,2,2,4,3,6] ...but of course you really get a list of lists: [[0, 0], [1, 2], [2, 4], [3, 6]] I'm aware I can use any of the standard "flatten" bits of code to turn this back into what I want, but I was hoping there's some way to avoid the "lists of lists" generation in the first place? >>[x*y for x in range(4) for y in 1,2] [0, 0, 1, 2, 2, 4, 3, 6] A slightly similar problem: If I want to "merge," say, list1=[1,2,3] with list2=[4,5,6] to obtain [1,4,2,5,3,6], is there some clever way with "zip" to do so? >>items = [None] * 6items[::2] = 1,2,3items[1::2] = 4,5,6items [1, 4, 2, 5, 3, 6] Peter Jun 27 '08 #3

 P: n/a Joel Koltner wrote: Is there an easy way to get a list comprehension to produce a flat list of, say, [x,2*x] for each input argument? E.g., I'd like to do something like: [ [x,2*x] for x in range(4) ] ...and receive [ 0,0,1,2,2,4,3,6] ...but of course you really get a list of lists: [[0, 0], [1, 2], [2, 4], [3, 6]] I'm aware I can use any of the standard "flatten" bits of code to turn this back into what I want, but I was hoping there's some way to avoid the "lists of lists" generation in the first place? A slightly similar problem: If I want to "merge," say, list1=[1,2,3] with list2=[4,5,6] to obtain [1,4,2,5,3,6], is there some clever way with "zip" to do so? Thanks, ---Joel -- http://mail.python.org/mailman/listinfo/python-list For the first part: def gen(n): for i in xrange(n): yield i yield 2*i print list(gen(4)) [0, 0, 1, 2, 2, 4, 3, 6] gerard Jun 27 '08 #4

 P: n/a "Joel Koltner"

 P: n/a On Thu, 22 May 2008 15:29:42 -0400, inhahe wrote: "Joel Koltner" Is there an easy way to get a list comprehension to produce a flat listof, say, [x,2*x] for each input argument?E.g., I'd like to do something like:[ [x,2*x] for x in range(4) ]...and receive[ 0,0,1,2,2,4,3,6]...but of course you really get a list of lists:[[0, 0], [1, 2], [2, 4], [3, 6]]I'm aware I can use any of the standard "flatten" bits of code to turnthis back into what I want, but I was hoping there's some way to avoidthe "lists of lists" generation in the first place?A slightly similar problem: If I want to "merge," say, list1=[1,2,3]with list2=[4,5,6] to obtain [1,4,2,5,3,6], is there some clever waywith "zip" to do so?Thanks,---Joel i figured out a solution sum([x,2*x] for x in range(4)],[]) #not tested sum(zip(list1,list2),()) #not tested (you did say you knew of ways to flatten, but i dunno if you knew of that way or not) as an aside, i wish that sum didn't have to take the second parameter. it's kind of superfluous. it can just use the first item as the initial value instead of 0 when no initial value is specified. it would be a little complex to do without putting a conditional in your main loop and slowing it down, but it could be done. If you don't want the second parameter use reduce(): >>reduce(operator.add, ([x, x*2] for x in xrange(4))) [0, 0, 1, 2, 2, 4, 3, 6] >>reduce(operator.add, zip([1,2,3],[4,5,6])) (1, 4, 2, 5, 3, 6) or: >>reduce(lambda x, y: x.extend(y) or x, ([x, x*2] for x in xrange(4))) [0, 0, 1, 2, 2, 4, 3, 6] -- Ivan Jun 27 '08 #6

 P: n/a Joel Koltner

 P: n/a "Peter Otten" <__*******@web.dewrote in message news:g1*************@news.t-online.com... >A slightly similar problem: If I want to "merge," say, list1=[1,2,3] ... >>>items = [None] * 6items[::2] = 1,2,3items[1::2] = 4,5,6items [1, 4, 2, 5, 3, 6] Thanks Peter, that's pretty clean -- I like it! Jun 27 '08 #8

 P: n/a "inhahe"

 P: n/a Hi Marc, "Marc Christiansen" >list1=[1,2,3]list2=[4,5,6][j for (i,m) in enumerate(list1) for j in (m,list2[i])] [1, 4, 2, 5, 3, 6] Not exactly "clean" due to having to enumerate list1 to get the index for list2. There may be a better method, of course -- so far I like Petter Otten's approach. Thanks for the help, ---Joel Jun 27 '08 #10

 P: n/a Peter Otten <__*******@web.dewrote: A slightly similar problem: If I want to "merge," say, list1=[1,2,3] with list2=[4,5,6] to obtain [1,4,2,5,3,6], is there some clever way with "zip" to do so? >items = [None] * 6items[::2] = 1,2,3items[1::2] = 4,5,6items [1, 4, 2, 5, 3, 6] My problem with this solution is that you depend on knowing how many elements you have in each list ahead of time. Assuming that both list are of the same length, then, I find the following more elegant: list1=[1,2,3] list2=[4,5,6] reduce(lambda x, y: x+y, zip(list1, list2)) of course, zip creates tuples, so you end up with a tuple, therefore if you need for your solution to be a list: list(reduce(lambda x, y: x+y, zip(list1, list2))) of reduce(lambda x, y: x+y, list(zip(list1, list2)) ) Yves. http://www.SollerS.ca Jun 27 '08 #11

 P: n/a Yves Dorfsman wrote: Peter Otten <__*******@web.dewrote: A slightly similar problem: If I want to "merge," say, list1=[1,2,3] with list2=[4,5,6] to obtain [1,4,2,5,3,6], is there some clever way with "zip" to do so? >>items = [None] * 6items[::2] = 1,2,3items[1::2] = 4,5,6items [1, 4, 2, 5, 3, 6] My problem with this solution is that you depend on knowing how many elements you have in each list ahead of time. \$ python -m timeit -s"a = [1,2,3]*100; b = [4,5,6]*100; from operator import add" "list(reduce(add, zip(a, b)))" 1000 loops, best of 3: 637 usec per loop \$ python -m timeit -s"a = [1,2,3]*100; b = [4,5,6]*100" "items=[None]*(2*len(a)); items[::2] = a; items[1::2] = b" 10000 loops, best of 3: 23.4 usec per loop The speed gain is significant. Why should I throw away useful information if I have it? I'd even be willing to convert one arbitrary iterable to a list to get the length information. \$ python -m timeit -s"a = [1,2,3]*100; b = [4,5,6]*100" "aa = list(a); items=[None]*(2*len(aa)); items[::2] = aa; items[1::2] = b" 10000 loops, best of 3: 29.5 usec per loop Assuming that both list are of the same length, then, I find the following more elegant: list1=[1,2,3] list2=[4,5,6] reduce(lambda x, y: x+y, zip(list1, list2)) of course, zip creates tuples, so you end up with a tuple, therefore if you need for your solution to be a list: list(reduce(lambda x, y: x+y, zip(list1, list2))) I'd rather use a plain old for-loop: >>from itertools import izipa = [1,2,3]b = [4,5,6]items = []for chunk in izip(a, b): .... items.extend(chunk) .... >>items [1, 4, 2, 5, 3, 6] \$ python -m timeit -s"a = [1,2,3]*100; b = [4,5,6]*100; from itertools import izip" "items = [] for chunk in izip(a, b): items.extend(chunk)" 1000 loops, best of 3: 242 usec per loop \$ python -m timeit -s"a = [1,2,3]*100; b = [4,5,6]*100; from itertools import izip" "items = []; extend = items.extend for chunk in izip(a, b): extend(chunk)" 10000 loops, best of 3: 70.9 usec per loop reduce(lambda x, y: x+y, list(zip(list1, list2)) ) list(zip(...)) has no effect here. Possible fixes >>reduce(lambda x, y: x + list(y), zip(list1, list2), []) [1, 4, 2, 5, 3, 6] >>reduce(lambda x, y: x.extend(y) or x, zip(list1, list2), []) [1, 4, 2, 5, 3, 6] \$ python -m timeit -s"a = [1,2,3]*100; b = [4,5,6]*100" "reduce(lambda x, y: x.extend(y) or x, zip(a, b), [])" 1000 loops, best of 3: 368 usec per loop are more complicated than elegant. Not recommended. Peter Jun 27 '08 #12

 P: n/a Peter Otten <__*******@web.dewrote: The speed gain is significant. Why should I throw away useful information if I have it? My thinking was that it wasn't generic enough, and I was looking for a solution that would work for more generic problem. I agree, I shouldn't have used the world "elegant" here, more generic would have been better. I'd even be willing to convert one arbitrary iterable to a list to get the length information. \$ python -m timeit -s"a = [1,2,3]*100; b = [4,5,6]*100" "aa = list(a); items=[None]*(2*len(aa)); items[::2] = aa; items[1::2] = b" 10000 loops, best of 3: 29.5 usec per loop Yes, I like that, it is as generic as the reduce one. are more complicated than elegant. Not recommended. You proved your point. Every book and webpage out there says that functional solutions are faster than loops, that's why I tried hard not to use a loop, and "reduce" is considered functional - I should have timed it. Yves. http://www.SollerS.ca Jun 27 '08 #13

 P: n/a On May 22, 7:21 pm, "Joel Koltner" wrote: Is there an easy way to get a list comprehension to produce a flat list of, say, [x,2*x] for each input argument? E.g., I'd like to do something like: [ [x,2*x] for x in range(4) ] [x * i for x in xrange(4) for i in xrange(1, 3)] -- Paul Hankin Jun 27 '08 #14

### This discussion thread is closed

Replies have been disabled for this discussion.