Anatoly
Anatoly

Reputation: 89

How to group lists inside a list by first element?

I have a list of lists that looks like this:

big_list = [[0,5,70],[0,3,20],[0,4,60],[0,6,30],    
            [1,6,50],[1,4,30],[1,3,70],        
            [2,4,20],[2,5,40],
            [69,420,20]]

How do I turn it into this list, where all of the lists are grouped together into lists by the first number in every list:

big_list_sorted = [[[0,5,70],[0,3,20],[0,4,60],[0,6,30]],
                   [[1,6,50],[1,4,30],[1,3,70]],
                   [[2,4,20],[2,5,40]],
                   [[69,420,20]]]

Also, here I put lists in the original big_list in order for readability, but they would not be in order.

Upvotes: 2

Views: 3527

Answers (6)

Paul Panzer
Paul Panzer

Reputation: 53029

It's a minor stylistic thing but you can avoid the ugly lambda x: x[0] many answers are opting for and use operator.itemgetter instead.

from random import shuffle
from itertools import groupby
from operator import itemgetter

big_list = [[0,5,70],[0,3,50],[0,4,60],[0,6,30],    
            [1,6,50],[1,4,30],[1,3,70],        
            [2,4,20],[2,5,40],
            [69,420,20]]

shuffle(big_list)

[*map(list,map(itemgetter(1),groupby(sorted(big_list),itemgetter(0))))]

# [[[0, 3, 50], [0, 4, 60], [0, 5, 70], [0, 6, 30]], [[1, 3, 70], [1, 4, 30], [1, 6, 50]], [[2, 4, 20], [2, 5, 40]], [[69, 420, 20]]]

Upvotes: 0

CristiFati
CristiFati

Reputation: 41116

You could use [Python 3.Docs]: itertools - Functions creating iterators for efficient looping.

Group the (inner) lists (via groupby), on their 1st element, in the sorted initial list:

>>> import itertools
>>>
>>> big_list
[[0, 5, 70], [0, 3, 50], [0, 4, 60], [0, 6, 30], [1, 6, 50], [1, 4, 30], [1, 3, 70], [2, 4, 20], [2, 5, 40], [69, 420, 20]]
>>>
>>> [list(item[1]) for item in itertools.groupby(sorted(big_list), key=lambda x: x[0])]
[[[0, 3, 50], [0, 4, 60], [0, 5, 70], [0, 6, 30]], [[1, 3, 70], [1, 4, 30], [1, 6, 50]], [[2, 4, 20], [2, 5, 40]], [[69, 420, 20]]]

As a side note (might be a typo), the 1st element in the desired output ([0, 3, 20]) is not present in the input.

Upvotes: 1

slider
slider

Reputation: 12990

You can group lists in a dictionary by their first element and get the result using .values():

groups = {}
for l in big_list:
    groups.setdefault(l[0], []).append(l)

big_list_sorted = list(groups.values())
print(big_list_sorted)
# [[[0, 5, 70], [0, 3, 50], [0, 4, 60], [0, 6, 30]], [[1, 6, 50], [1, 4, 30], [1, 3, 70]], [[2, 4, 20], [2, 5, 40]], [[69, 420, 20]]]

Upvotes: 5

wonton
wonton

Reputation: 8247

You can use itertools.groupby to accomplish this.

First you sort the array by the first element.

big_list = sorted(big_list)

Next you apply groupby to split them into subarrays keyed on the first element.

itertools.groupby(big_list, key=lambda x:x[0])

At this point you have something that looks like

[(0, <itertools._grouper object at 0x107bcf390>), (1, <itertools._grouper object at 0x107bcf310>), (2, <itertools._grouper object at 0x107bcf250>), (69, <itertools._grouper object at 0x107bcf2d0>)]

In the tuple, the grouper objects at index 1 contains the elements matching the key at index 0. Now you can just create an array using index 1 of each tuple.

[list(g) for i, g in itertools.groupby(big_list, lambda x: x[0])]

Upvotes: 1

Beth Crane
Beth Crane

Reputation: 623

You need a custom sort based on the first element of each list.

big_list.sort(key=lambda x: x[0])

You can read about sorting here: https://wiki.python.org/moin/HowTo/Sorting

Upvotes: -1

bug
bug

Reputation: 4140

You can use itertools.groupby

>>> from itertools import groupby
>>> [list(g) for _, g in groupby(big_list, lambda l: l[0])]
[[[0, 5, 70], [0, 3, 50], [0, 4, 60], [0, 6, 30]], [[1, 6, 50], [1, 4, 30], [1, 3, 70]], [[2, 4, 20], [2, 5, 40]], [[69, 420, 20]]]

Note: you can void to use list, it's there only to make the output more readable as groupby returns an iterator.

Upvotes: 1

Related Questions