views:

278

answers:

5

I want to convert a tuples list into a nested list using Python. How do I do that?

I have a sorted list of tuples (sorted by the second value):

[(1, 5),  (5, 4), (13, 3), (4, 3), (3, 2), (14, 1), (12, 1), 
 (10, 1), (9, 1), (8, 1),  (7, 1), (6, 1), (2, 1)]

Now I want it to have like this (second value ignored and nested in lists):

[ [1], [5], [13, 4], [3], [14, 12, 10, 9, 8, 7, 6, 2] ]

I've seen other threads in here with map used for such things, but I don't completely understand it. Can anyone provide insight as to the 'correct' python way of doing this?

A: 

Don't know how fast this will be for bigger sets, but you could do something like that:

input = [
    (1,  5), (5,  4), (13, 3), (4, 3), (3, 2), (14, 1),
    (12, 1), (10, 1), (9,  1), (8, 1), (7, 1), (6,  1),
    (2,  1)
]

output = [[] for _ in xrange(input[0][1])]
for value, key in input:
    output[-key].append(value)

print output # => [[1], [5], [13, 4], [3], [14, 12, 10, 9, 8, 7, 6, 2]]
PiotrLegnica
You are assuming that len(output) should match the highest key value, and that the key values are always consecutive.
ironfroggy
Yeah, I assumed that OP want indexes in `input` and `output` to match - so if you take e.g. `(3, 2)` out of `input`, then `output[-2]` will be an empty list. Hard to say with just one dataset.
PiotrLegnica
+10  A: 
from operator import itemgetter
from itertools import groupby

lst = [(1, 5),  (5, 4), (13, 3), (4, 3), (3, 2), (14, 1),
       (12, 1), (10, 1), (9, 1), (8, 1),  (7, 1), (6, 1), (2, 1)]

result = [[x for x, y in group]
          for key, group in groupby(lst, key=itemgetter(1))]

groupby(lst, key=itemgetter(1)) generates groups of consecutive elements of lst within which all elements have the same 1st (counting from zero) item. The [x for x, y in group] keeps the 0th item of each element within each group.

Roberto Bonvallet
i liked this. simple and without mapping.
proxylittle
oh ignore its. nvm.. typo.
proxylittle
Probably `sort` is a list of integers and not a list of 2-tuples.
Roberto Bonvallet
`groupby` requires the `lst` to be sorted: `lst.sort(key=itemgetter(1))`.
J.F. Sebastian
as i said.. it was a typo sorry. took the wrong list into the function. But thanks for the fast comments :)
proxylittle
+2  A: 

It is a bit convoluted, but you can do it with the itertools.groupby function:

>>> lst = [(1, 5),  (5, 4), (13, 3), (4, 3), (3, 2), (14, 1), (12, 1), 
 (10, 1), (9, 1), (8, 1),  (7, 1), (6, 1), (2, 1)]
>>> from operator import itemgetter 
>>> import itertools
>>> [map(itemgetter(0), group) for (key,group) in itertools.groupby(lst, itemgetter(1))]
[[1], [5], [13, 4], [3], [14, 12, 10, 9, 8, 7, 6, 2]]
>>>

Explanation: groupby returns an iterator for each group, where a group is defined as a sequence of entries that have the same value returned by function passed as a separate parameter. itemgetter(1) generates a function that returns x[1] when called with argument x. Since the groupby iterator returns two values - the key that was used and sequences of the original values which are tuples, we then need to strip out the second value in each tuple, which is what map(itemgetter(0), group) does.

Dave Kirby
good aswell but your last line is confusing, caus i need to learn the mappingstuff alittle. And i think its almost the same roberto posted. But thanks!
proxylittle
+1  A: 

Maybe not the most pythonesque answer, but this works:

d = {}

a = [(1,5), (5,4), (13,3), (4,3), (3,2), (14,1), (12,1)]

for value in a:
     if value[0] not in d:
         d[ value[0] ] = []
     d[ value[0] ].append( a[1] )

print d.values()
extraneon
I would improve this with setdefault() instead of the check on `value[0] not in d`
ironfroggy
+1  A: 

The simple solution:

n_list = []
c_snd = None
for (fst, snd) in o_list:
  if snd == c_snd: n_list[-1].append(fst)
  else:
    c_snd = snd
    n_list.append([fst])

Explanation: use c_snd to store the current second part of the tuple. If that changes, start a new list in n_list for this new second value, starting with fst, otherwise add fst to the last list in n_list.

me_and