Search code examples
pythonarrayslambdasplit

In python, how to group elements together, based on a key (group adjacent)?


In python, I'd like to group elements together based on a key (in example below, key is second element, or element[1]).

initial_array = [[10, 0], [30, 0], [40, 2], [20, 2], [90, 0], [80, 0]]

Only elements which keys are the same and that are adjacent should be grouped together.

splited_array = [ [[10, 0], [30, 0]], 
                  [[40, 2], [20, 2]], 
                  [[90, 0], [80, 0]] ]

Additionally, i'd like the element that caused the split to be also at the end of the previous array.

splited_array = [ [[10, 0], [30, 0], [40, 2]], 
                  [[40, 2], [20, 2], [90, 0]], 
                  [[90, 0], [80, 0]] ]

What is the easiest way to do that in python ? (re-using Built-in Functions if possible)


Solution

  • You can use itertools.groupby:

    >>> from itertools import groupby
    >>> from operator import itemgetter
    >>> lis = [[10, 0], [30, 0], [40, 2], [20, 2], [90, 0], [80, 0]]
    >>> [list(g) for k,g in groupby(lis, key=itemgetter(1))]
    [[[10, 0], [30, 0]],
     [[40, 2], [20, 2]],
     [[90, 0], [80, 0]]]
    

    For second one:

    >>> ans = []
    for k,g in groupby(lis, key=itemgetter(1)):
        l = list(g)
        ans.append(l)
        if len(ans) > 1:
            ans[-2].append(l[0])
    ...         
    >>> ans
    [[[10, 0], [30, 0], [40, 2]],
     [[40, 2], [20, 2], [90, 0]],
     [[90, 0], [80, 0]]]
    

    Update:

    >>> from itertools import zip_longest
    >>> lis = [[[10, 0], [30, 0]],
     [[40, 2], [20, 2]],
     [[90, 0], [80, 0]]]
    >>> [x + ([y[0]] if y else []) for x,y in 
                                            zip_longest(lis,lis[1:])]
    [[[10, 0], [30, 0], [40, 2]],
     [[40, 2], [20, 2], [90, 0]],
     [[90, 0], [80, 0]]]