4
>>> 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"?

nneonneo
  • 171,345
  • 36
  • 312
  • 383
Ozooha Ozooha
  • 73
  • 1
  • 8

3 Answers3

6

You could try something like this:

result = [tuple([ai, bi] + ci) for ai, bi, ci in zip(a, b, c)]
nneonneo
  • 171,345
  • 36
  • 312
  • 383
2

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)]
Community
  • 1
  • 1
senderle
  • 145,869
  • 36
  • 209
  • 233
-2

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) ]
Joe M.
  • 609
  • 3
  • 11
  • 2
    Sometimes, people specify example input, and not actual input. So this seems like an overly-specific solution. – nneonneo Sep 29 '12 at 18:04
  • Depending on what you mean by succint. The first option does not contain the input, so if by succint we mean shortness and compactness to produce result, it is not so good. The purpose of lambda was to reuse `x`, so I think this is not really unneeded - compared with writing the eq. twice. I however agree that I have probably misunderstood the direction of the question. – Joe M. Sep 29 '12 at 18:18
  • Thank you for all your efforts though and yes this was just a toy example. – Ozooha Ozooha Sep 29 '12 at 18:47
  • Succinct almost never refers to the inputs. In real code, you rarely get to control the messiness of the inputs. Succinctness almost always refers to elegant / concise / efficient ways to handle the inputs after they are already formed. This is not a golden rule; *sometimes* the clarity of input handling is valuable, but clearly not needed in a case like this where the inputs are just made up lists to illustrate the zipping problem. – ely Sep 29 '12 at 18:48