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

# convert list of tuples into several lists

 P: n/a Hi, I can find examples to convert lists into a list of tuples like: map(None,[1,2,3],[4,5,6]) [(1,4),(2,5),(3,6)] but how is it done vice versa? Oliver Jul 18 '05 #1
19 Replies

 P: n/a zip(*[(1,4),(2,5),(3,6)]) -- Regards, Diez B. Roggisch Jul 18 '05 #2

 P: n/a Diez B. Roggisch wrote: zip(*[(1,4),(2,5),(3,6)]) Thanks :) I knew it must be simple. The asterics - thing was new to me. By the way: What is faster? this: z = [(1,4),(2,5),(3,6) a,b = zip(*[(x[0], x[0]-x[1]) for x in z]) or: a = [] b = [] for x in z: a.append(x[0]) b.append(x[0]-x[1]) I guess first, isn't it? Oliver Jul 18 '05 #3

 P: n/a Oliver Eichler a écrit : Diez B. Roggisch wrote:zip(*[(1,4),(2,5),(3,6)]) Thanks :) I knew it must be simple. The asterics - thing was new to me. By the way: What is faster? this: z = [(1,4),(2,5),(3,6) a,b = zip(*[(x[0], x[0]-x[1]) for x in z]) or: a = [] b = [] for x in z: a.append(x[0]) b.append(x[0]-x[1]) I guess first, isn't it? Oliver Best answer is : try it :) use the "timeit" module (in the standard lib) to do so ... Pierre Jul 18 '05 #4

 P: n/a Le mercredi 9 Février 2005 14:46, Diez B. Roggisch a écrit*: zip(*[(1,4),(2,5),(3,6)]) -- Regards, Diez B. Roggisch That's incredibly clever! I would had never thought to use "zip" to do this! I would had only think to use it for the contrary, i.e. zip([1,2,3], [4,5,6]) [(1, 4), (2, 5), (3, 6)] Notice though that the solution doesn't yield the exact contrary as we end up with a list of tuples instead of a list of lists : zip(*[(1,4),(2,5),(3,6)]) [(1, 2, 3), (4, 5, 6)] But this can be easily fix if lists are really wanted : map(list, zip(*[(1,4),(2,5),(3,6)])) [[1, 2, 3], [4, 5, 6]] Anyway, I find Diez solution brillant ! I'm always amazed to see how skilled a programmer can get when comes the time to find a short and sweet solution. One can admire that zip(*zip(*a_list_of_tuples)) == a_list_of_tuples Thank you You gave me much to enjoy Francis girard Jul 18 '05 #5

 P: n/a Diez B. Roggisch wrote: zip(*[(1,4),(2,5),(3,6)]) While this is also the approach I would use, it is worth noting that Guido thinks of this as an abuse of the argument passing machinery: http://mail.python.org/pipermail/pyt...ly/037346.html Steve Jul 18 '05 #6

 P: n/a Steven Bethard wrote: Diez B. Roggisch wrote: zip(*[(1,4),(2,5),(3,6)]) While this is also the approach I would use, it is worth noting that Guido thinks of this as an abuse of the argument passing machinery: http://mail.python.org/pipermail/pyt...ly/037346.html I'm not sure that's the same thread I already read where he dissed zip like that, but what I'm wondering is what is the alternative? Is there an equally elegant approach that doesn't "abuse" the argument passing machinery? -Peter Jul 18 '05 #7

 P: n/a Peter Hansen wrote: Steven Bethard wrote: Diez B. Roggisch wrote: zip(*[(1,4),(2,5),(3,6)]) While this is also the approach I would use, it is worth noting that Guido thinks of this as an abuse of the argument passing machinery: http://mail.python.org/pipermail/pyt...ly/037346.html I'm not sure that's the same thread I already read where he dissed zip like that, but what I'm wondering is what is the alternative? Is there an equally elegant approach that doesn't "abuse" the argument passing machinery? I know I found it in another thread before. I think he's said it a few times. Personally, I wish that, if we're not to use zip like this, that Python would provide a builtin 'unzip' to do the corresponding thing. If you're interested in a recipe that does this, you can look at my 'starzip' recipe which is basically 'unzip' for iterators: http://aspn.activestate.com/ASPN/Coo.../Recipe/302325 I guess if we wanted a standard solution to the 'unzip' problem, I could rally for this to be added to itertools, but I'm not sure I'm up to the task of rewriting it in C... Steve Jul 18 '05 #8

 P: n/a What does the leading * do? Jul 18 '05 #9

 P: n/a Cappy2112 wrote: What does the leading * do? Tells Python to use the following iterable as the (remainder of the) argument list: py> def f(x, y): .... print x, y .... py> f([1, 2]) Traceback (most recent call last): File "", line 1, in ? TypeError: f() takes exactly 2 arguments (1 given) py> f(*[1, 2]) 1 2 py> f(1, [2]) 1 [2] py> f(1, *[2]) 1 2 Note that whenever the leading * is present, the following list gets expanded into the positional arguments of f -- x and y. Steve Jul 18 '05 #10

 P: n/a Pierre Barbier de Reuille wrote: Best answer is : try it :) use the "timeit" module (in the standard lib) to do so ... Ok, import timeit s = """\ a,b,c1,c2 = zip(*[(x[2],x[4], x[2]-x[1], x[2] - x[3]) for x in z]) """ t = timeit.Timer(stmt=s,setup="z = [(1,2,3,4,5)]*1000") print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000) s ="""\ for x in z: a = x[2] b = x[4] c1 = x[2] - x[1] c2 = x[2] - x[3] """ t = timeit.Timer(stmt=s,setup="z = [(1,2,3,4,5)]*1000") print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000) for 30 elements: oeichler@frog:~/tmp> python test.py 32.90 usec/pass 21.53 usec/pass for 100 elements: oeichler@frog:~/tmp> python test.py 103.32 usec/pass 70.91 usec/pass for 100 elements: oeichler@frog:~/tmp> python test.py 1435.43 usec/pass 710.55 usec/pass What do we learn? It might look elegant but it is slow. I guess mainly because I do the iteration twice with the zip command. The 1000 element run seems to show what Guido means with "abuse of the argument passing machinery" Learned my lesson :) Thanks to all Oliver Jul 18 '05 #11

 P: n/a Pierre Barbier de Reuille wrote: Best answer is : try it :) use the "timeit" module (in the standard lib) to do so ... Ok, (a second time. I hope the first post was cancelled as it was false) import timeit s = """\ a,b,c1,c2 = zip(*[(x[2],x[4], x[2]-x[1], x[2] - x[3]) for x in z]) """ t = timeit.Timer(stmt=s,setup="z = [(1,2,3,4,5)]*1000") print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000) s ="""\ a = [] b = [] c1 = [] c2 = [] for x in z: a.append(x[2]) b.append(x[4]) c1.append(x[2] - x[1]) c2.append(x[2] - x[3]) """ t = timeit.Timer(stmt=s,setup="z = [(1,2,3,4,5)]*1000") print "%.2f usec/pass" % (1000000 * t.timeit(number=100000)/100000) for 100 elements: oeichler@frog:~/tmp> python test.py 104.67 usec/pass 180.19 usec/pass for 1000 elements: oeichler@frog:~/tmp> python test.py 1432.06 usec/pass 1768.58 usec/pass What do we learn? The zip-thingy is even faster than the for loop Learned my lesson :) Thanks to all Oliver Jul 18 '05 #12

 P: n/a Cappy2112 wrote: What does the leading * do? It causes the list/tuple following the * to be unpacked into function arguments. Eg zip(*[(1, 2, 3), (4, 5, 6)]) [(1, 4), (2, 5), (3, 6)] is the same as zip((1, 2, 3), (4, 5, 6)) [(1, 4), (2, 5), (3, 6)] The * should make you think of dereferencing things (eg pointer de-reference in C). Its equivalent to the now deprecated apply function which does the same thing in a more wordy fashion, ie apply the list as parameters to the function. apply(zip, [(1, 2, 3), (4, 5, 6)]) [(1, 4), (2, 5), (3, 6)] -- Nick Craig-Wood -- http://www.craig-wood.com/nick Jul 18 '05 #13

 P: n/a Steven Bethard wrote: Peter Hansen wrote: Steven Bethard wrote: Diez B. Roggisch wrote: zip(*[(1,4),(2,5),(3,6)]) While this is also the approach I would use, it is worth noting that Guido thinks of this as an abuse of the argument passing machinery: http://mail.python.org/pipermail/pyt...ly/037346.html I'm not sure that's the same thread I already read where he dissed zip like that, but what I'm wondering is what is the alternative? Is there an equally elegant approach that doesn't "abuse" the argument passing machinery? I know I found it in another thread before. I think he's said it a few times. Personally, I wish that, if we're not to use zip like this, that Python would provide a builtin 'unzip' to do the corresponding thing. I never really got the impression that Guido was particularly *strongly* opposed to this use of the extended call syntax. Merely that he was concerned that it would break down if the relevant list turned out to be large (that is, the abuse is using *args with a list when the list may turn out to be large, not a problem specifically with using the star syntax with zip()). Maybe he's been more explicit somewhere, and I just never saw it. Anyway, his concern seems justified, as my understanding is that func(*iterable) is roughly equivalent to func(*tuple(iterable)), which can be rather expensive when the iterable is a long list of tuples. So zip(*zip(*iterable)) is actually zip(*tuple(zip(*tuple(iterable)))). That's potentially an awful lot of data copying for an identity operation :) Anyway, I think it does make a decent case for an itertools.iunzip or some such beast. Cheers, Nick. -- Nick Coghlan | nc******@email.com | Brisbane, Australia --------------------------------------------------------------- http://boredomandlaziness.skystorm.net Jul 18 '05 #14

 P: n/a Nick Coghlan wrote: I never really got the impression that Guido was particularly *strongly* opposed to this use of the extended call syntax. Merely that he was concerned that it would break down if the relevant list turned out to be large (that is, the abuse is using *args with a list when the list may turn out to be large, not a problem specifically with using the star syntax with zip()). Is there some unexpected limit to the number of arguments that may be passed with the *args format (say, "256 function arguments maximum are supported by Python"), or is this concern just because of the raw memory inherently used by the tuple? In other words, if one is confident that one can whip tuples of the required size around without using up available memory, would there still be such a concern about the *args "abuse"? -Peter Jul 18 '05 #15

 P: n/a Thanks I dont remember reading anything about this. What is this feature called? Steven Bethard wrote: Cappy2112 wrote: What does the leading * do? Tells Python to use the following iterable as the (remainder of the) argument list: Jul 18 '05 #16

 P: n/a Steven Bethard a écrit : Cappy2112 wrote: What does the leading * do? Tells Python to use the following iterable as the (remainder of the) argument list: Could someone explain why this doesn't work : Python 2.3.2 (#49, Oct 2 2003, 20:02:00) [MSC v.1200 32 bit (Intel)] on win32 Type "help", "copyright", "credits" or "license" for more information. def f(*args,**kw): .... print args, kw .... f(*[1,2]) (1, 2) {} f(*[1,2],x=1) File "", line 1 f(*[1,2],x=1) ^ SyntaxError: invalid syntax Pierre Jul 18 '05 #17

 P: n/a On Fri, 11 Feb 2005 07:35:43 +0100, Pierre Quentel wrote: Steven Bethard a écrit : Cappy2112 wrote: What does the leading * do? Tells Python to use the following iterable as the (remainder of the) argument list: Could someone explain why this doesn't work : Python 2.3.2 (#49, Oct 2 2003, 20:02:00) [MSC v.1200 32 bit (Intel)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> def f(*args,**kw): ... print args, kw ... >>> f(*[1,2]) (1, 2) {} >>> f(*[1,2],x=1) File "", line 1 f(*[1,2],x=1) ^ SyntaxError: invalid syntax the * and ** must occur at the end. f(x=1, *[1,2]) is valid. Stephen. Jul 18 '05 #18

 P: n/a Peter Hansen wrote: Is there some unexpected limit to the number of arguments that may be passed with the *args format (say, "256 function arguments maximum are supported by Python"), or is this concern just because of the raw memory inherently used by the tuple? In other words, if one is confident that one can whip tuples of the required size around without using up available memory, would there still be such a concern about the *args "abuse"? I'm not aware of any arbitrary limits in that code, since it does pass real tuple objects around. Then again, it's not an area of the code I'm particularly familiar with. . . However, if there was a limit other than the amount of available memory though, I expect Guido would have said so explicitly. As it is, the concern seems to be that there is a potentially large copy operation triggered by an innocent looking function call. Cheers, Nick. -- Nick Coghlan | nc******@email.com | Brisbane, Australia --------------------------------------------------------------- http://boredomandlaziness.skystorm.net Jul 18 '05 #19

 P: n/a Pierre Quentel wrote: Could someone explain why this doesn't work : Python 2.3.2 (#49, Oct 2 2003, 20:02:00) [MSC v.1200 32 bit (Intel)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> def f(*args,**kw): ... print args, kw ... >>> f(*[1,2]) (1, 2) {} >>> f(*[1,2],x=1) File "", line 1 f(*[1,2],x=1) ^ SyntaxError: invalid syntax >>> http://docs.python.org/ref/calls.html Steve Jul 18 '05 #20

### This discussion thread is closed

Replies have been disabled for this discussion.