Reputation: 571
I really searched for this one, because I am almost certain some variation has been asked before but I couldn't put in the correct terms into Google to get a result that matches what I am trying to do. Generally seems like people are looking for the total combinations without constraints.
I am trying to do the following:
Given a list like this:
[1, 1, 2, 2, 3, 3]
group it into as many groups of [1, 2, 3]
as possible
So
[1, 1, 2, 2, 3, 3]
-> [[1, 2, 3], [1, 2, 3]]
[1, 1, 2, 3, 3]
-> [[1, 2, 3], [1, 3]]
[1, 1, 3, 3, 5]
-> [[1, 3, 5], [1, 3]]
[1, 4, 4, 7]
-> [[1, 4, 7], [4]]
Notes:
Input will always be sorted, but the values of these numbers is not known, so it will need to work in general sense.
The idea is I have objects with certain attributes that need to be grouped together to create a different object, but sometimes I am given repeats (and potentially incomplete repeats) -- ie, I used to think that the attributes of my objects will always just be [1, 2, 3]
but turns out sometimes I can get [1, 1, 2, 2, 3, 3]
and I need a way to break that into two [1, 2, 3]
lists to create an intermediate object downstream.
Upvotes: 3
Views: 463
Reputation: 120409
You can use zip_longest
and groupby
from itertools
:
from itertools import zip_longest, groupby
def f(l):
z = zip_longest(*[list(g) for _, g in groupby(l)])
return [[j for j in i if j is not None] for i in z]
Usage:
>>> f([1, 1, 2, 2, 3, 3])
[[1, 2, 3], [1, 2, 3]]
>>> f([1, 1, 2, 3, 3])
[[1, 2, 3], [1, 3]]
>>> f([1, 1, 3, 3, 5])
[[1, 3, 5], [1, 3]]
>>> f([1, 4, 4, 7])
[[1, 4, 7], [4]]
# Update
>>> f(sorted([1, 1, 2, 2, 3, 3, 1, 2]))
[[1, 2, 3], [1, 2, 3], [1, 2]]
# Update 2
>>> f([1, 1, 1, 2, 2, 2, 3, 3])
[[1, 2, 3], [1, 2, 3], [1, 2]]
Update
Alternative version suggested by @cards using filterfalse
:
from itertools import zip_longest, groupby, filterfalse
def f(l):
z = zip_longest(*[list(g) for _, g in groupby(l)])
return [list(filterfalse(lambda j: j is None, i)) for i in z]
Upvotes: 5