5

I have some list that consist of a tuples like this

one = [(4, 'a'), (3, 'b'), (2, 'c'), (3, 'd'), (5, 'e'), (6, 'f')]

and i want to group item on list one based on that integer to create new array that has an output like this

final = [(g1, 2, ['c']), (g2, 3, ['b','d']), (g3, 4, ['a']), (g4, 5, ['e']), (g5, 6, ['f'])]

I have no idea in creating the final list. How is python doing that? Any ideas would be appreciated. Thank you.

Note: g1, g2, and so on is just some string with increment.

thefourtheye
  • 233,700
  • 52
  • 457
  • 497
Sonic Master
  • 1,238
  • 2
  • 22
  • 36

3 Answers3

9

Since you want the output to be sorted, you can sort the original list based on the first element

>>> first = lambda x: x[0]
>>> one_sorted = sorted(one, key=first)

then you can group the elements based on the first elements with itertools.groupby, like this

groupby(one_sorted, first)

since you want to assign numbers, in ascending order, to the groups, you can wrap it with enumerate like this

enumerate(groupby(one_sorted, first), 1)

then you can unpack the result of enumerate in a for loop, like this

for index, (item, group) in enumerate(groupby(one_sorted, first), 1)

now you just have to construct the result list. You can use list comprehension to do that, like this

>>> from itertools import groupby
>>> [(index, item, [j[1] for j in group])
...     for index, (item, group) in enumerate(groupby(one_sorted, first), 1)]
[(1, 2, ['c']), (2, 3, ['b', 'd']), (3, 4, ['a']), (4, 5, ['e']), (5, 6, ['f'])]

[j[1] for j in group] actually iterates the grouped items and fetches the second item, which is the actual string.


Alternatively, you can group the elements in a dictionary, like this

>>> groups = {}
>>> for number, string in one:
...     groups.setdefault(number, []).append(string)
...     
... 
>>> groups
{2: ['c'], 3: ['b', 'd'], 4: ['a'], 5: ['e'], 6: ['f']}

and then return apply the enumerate on the sorted dictionary, like this

>>> [(index, number, groups[number])
...     for index, number in enumerate(sorted(groups), 1)]
[(1, 2, ['c']), (2, 3, ['b', 'd']), (3, 4, ['a']), (4, 5, ['e']), (5, 6, ['f'])]
thefourtheye
  • 233,700
  • 52
  • 457
  • 497
  • [(index, item, [j[1] for j in group]) for index, (item, group) in enumerate(groupby(one_sorted, first), 1)] that's work like a charm. But I do not understand, you constructed that list like a pro, lol. Thank you. – Sonic Master Mar 31 '15 at 04:14
  • Hi, i am sorry it'll be OOT but I want to know how if we doesn't sort the first list? I mean, we just 'group' that list. How is that possible? – Sonic Master Apr 03 '15 at 06:08
1

You can use a default dict to group the items:

from collections import defaultdict

# create dictionary # {2: ['c'], 3: ['b', 'd'], 4: ['a'], ...}
groups = defaultdict(list)
for k,v in one:
    groups[k].append(v)

# create sorted list [(1, (2, ['c'])), (2, (3, ['b', 'd'])), (3, (4, ['a'])), ...]
lists = enumerate(sorted(list(groups.items())), 1)

Note: The above produces an enumerator, which is generator-like object (see here). If you want to convert to a normal list just replace the last line with:

lists = [(i,k,v) for i,(k,v) in enumerate(sorted(list(groups.items())), 1)]
Community
  • 1
  • 1
bcorso
  • 45,608
  • 10
  • 63
  • 75
  • 1
    Promising, I printed lists and give me error "". Thank you – Sonic Master Mar 31 '15 at 04:30
  • @SonicMaster it's not an error. It's printing the enumerator object reference. However, if you need a list I've updated the answer to show how to convert to a normal list. – bcorso Mar 31 '15 at 15:03
0

I think the best solution would be to create a dictionary from int -> list. Go through the original list, if the int is a key then just add it to its list otherwise create a list with its value and add it to the dictionary.

kar288
  • 131
  • 3