Ozooha Ozooha
Ozooha Ozooha

Reputation: 83

Python: elegant way of creating a list of tuples?

>>> a=["a"]*4
>>> a
['a', 'a', 'a', 'a']
>>> b=range(4)
>>> b
[0, 1, 2, 3]
>>> c = [range(4,8), range(9,13), range(14,18), range(19,23)]
>>> c
[[4, 5, 6, 7], [9, 10, 11, 12], [14, 15, 16, 17], [19, 20, 21, 22]]
>>>
>>> result = map(lambda x,y:[x,y],a,b)
>>> map(lambda x,y:x.extend(y),result,c)
>>> result = map(tuple, result)
>>> result     # desired output: 
[('a', 0, 4, 5, 6, 7), ('a', 1, 9, 10, 11, 12), ('a', 2, 14, 15, 16, 17), ('a', 3, 19, 20, 21, 22)]
>>>
>>> try_test = zip(a,b,c)
>>> try_test # NOT DESIRED: leaves me with the list within the tuples
[('a', 0, [4, 5, 6, 7]), ('a', 1, [9, 10, 11, 12]), ('a', 2, [14, 15, 16, 17]), ('a', 3, [19, 20, 21, 22])]

I was wondering whether anyone has a more succinct way to do the "result"?

Upvotes: 4

Views: 6700

Answers (3)

senderle
senderle

Reputation: 151007

For a fully general approach to this problem, you might consider using one of the many variations on flatten you can find here, where flatten is a function that takes an arbitrarily nested iterable of iterables and returns a flat list of the items contained therein.

Then just map flatten over the zipped values of a, b, c and convert to tuple.

>>> from collections import Iterable
>>> def flatten(l):
...     for i in l:
...         if isinstance(i, Iterable) and not isinstance(i, basestring):
...             for sub in flatten(i):
...                 yield sub
...         else:
...             yield i
...
>>> map(tuple, map(flatten, zip(a, b, c)))
[('a', 0, 4, 5, 6, 7), ('a', 1, 9, 10, 11, 12), 
 ('a', 2, 14, 15, 16, 17), ('a', 3, 19, 20, 21, 22)]

Or even more succinctly, modify flatten to accept an arbitrary argument list and return a tuple. Then all you need is map:

>>> def flat_tuple(*args):
...     return tuple(flatten(args))
... 
>>> map(flat_tuple, a, b, c)
[('a', 0, 4, 5, 6, 7), ('a', 1, 9, 10, 11, 12), 
 ('a', 2, 14, 15, 16, 17), ('a', 3, 19, 20, 21, 22)]

If this is a one-off problem, the above approach is probably more trouble than it's worth. But if you've already defined flatten for other purposes, or if you're doing this frequently, the above could save you a lot of trouble!

Otherwise, just for the fun of it, here's a variation on nneonneo's answer that I like:

>>> [x + tuple(y) for x, y in zip(zip(a, b), c)]
[('a', 0, 4, 5, 6, 7), ('a', 1, 9, 10, 11, 12), 
 ('a', 2, 14, 15, 16, 17), ('a', 3, 19, 20, 21, 22)]

Upvotes: 2

Joe M.
Joe M.

Reputation: 609

For this very case: (if succinct == short)

q = lambda x : tuple(range(x,x+4))
res = [ ('a', num) + q(4*(num+1)+num) for num in xrange(4) ]

Upvotes: -2

nneonneo
nneonneo

Reputation: 179442

You could try something like this:

result = [tuple([ai, bi] + ci) for ai, bi, ci in zip(a, b, c)]

Upvotes: 6

Related Questions