3

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)

tigrou
  • 4,236
  • 5
  • 33
  • 59
  • I had temporarily changed the duplicate link on this to something that I thought was easier to understand, but it turns out that that version of the question had a different problem statement (and was in turn an inferior duplicate of something else). – Karl Knechtel Jan 02 '23 at 19:02

1 Answers1

4

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]]]
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
  • 2
    just for someone curious about `itemgetter`: `itemgetter(i) = lambda x: x[i]` – Saullo G. P. Castro Jul 07 '13 at 19:31
  • @AshwiniChaudhary i'm just reading your (excellent) answer. for second part, isn't there a way to do that in less imperative style, eg : without modifying a global state (ans variable), but by using a set of functions that take and return new sets of data (just like groupby() function). Hope you understand what i mean. – tigrou Jul 07 '13 at 20:07
  • Thanks for quick answer. This is what i was looking for. Anyway, I get "ImportError: cannot import name izip_longest" when executing "from itertools import izip_longest" under Blender 2.67 (Python 3.3). I tried same code under ideone.com (online compiler with Python 3 support) but get same error message. Any idea ? – tigrou Jul 07 '13 at 20:36
  • @tigrou use `zip_longest` in py3.x. – Ashwini Chaudhary Jul 07 '13 at 20:37