Reputation: 2227
I am wondering if it is possible to do grouping of lists in python in a simple way without importing any libraries.
and example of input could be:
a="0 0 1 2 1"
and output
[(0,0),(1,1),(2)]
I am thinking something like the implementation of itertools groupby
class groupby:
# [k for k, g in groupby('AAAABBBCCDAABBB')] --> A B C D A B
# [list(g) for k, g in groupby('AAAABBBCCD')] --> AAAA BBB CC D
def __init__(self, iterable, key=None):
if key is None:
key = lambda x: x
self.keyfunc = key
self.it = iter(iterable)
self.tgtkey = self.currkey = self.currvalue = object()
def __iter__(self):
return self
def __next__(self):
self.id = object()
while self.currkey == self.tgtkey:
self.currvalue = next(self.it) # Exit on StopIteration
self.currkey = self.keyfunc(self.currvalue)
self.tgtkey = self.currkey
return (self.currkey, self._grouper(self.tgtkey, self.id))
def _grouper(self, tgtkey, id):
while self.id is id and self.currkey == tgtkey:
yield self.currvalue
try:
self.currvalue = next(self.it)
except StopIteration:
return
self.currkey = self.keyfunc(self.currvalue)
but shorter
Upvotes: 0
Views: 165
Reputation: 42133
To group the items by value (as opposed to grouping by changes as itertools groupby would do), you can use a list comprehension that embeds a dictionary to organize the data into lists:
a="0 0 1 2 1"
groups = [ g[v] for g in [dict()] for v in map(int,a.split())
if g.setdefault(v,[]).append(v) or len(g[v])==1 ]
print(groups)
[[0, 0], [1, 1], [2]]
Each list (value in the internal (g
) dictionary) is augmented with the items in a
but only returned once (when encountering a new grouping key).
Using a dictionary to group the items avoids the need to sort the items (which would be required if using itertools.groupby)
If you want the grouping to work exactly like groupby, then the internal dictionary needs to be cleared when a new key is encountered:
groups = [ g.setdefault(v,g.clear() or [v])
for g in [dict()] for v in map(int,a.split())
if v not in g or g[v].append(v) ]
print(groups)
[[0, 0], [1], [2], [1]]
which you can expand to produce the same output as groupby (including computed grouping keys and working from an iterable:
a="0 0 1 2 1"
ia = map(int,a.split()) # an iterable
key = lambda v: v > 0 # a grouping key function
groups = [ (k,g.setdefault(k,g.clear() or [v]))
for g in [dict()] for v in ia for k in [key(v)]
if k not in g or g[k].append(v) ]
print(groups)
[(False, [0, 0]), (True, [1, 2, 1])]
Note that all the above solutions produce lists of grouped items (as opposed to grouby's item iterators
Upvotes: 1
Reputation: 2227
I just realized how to do it.
{k:[v for v in a.split() if v == k] for k in set(a.split())}
or
[tuple(v for v in a.split() if v == k) for k in set(a.split())]
however - this solution can not be used on dictionaties because dicts are not hashable - so maybe thats one of the reasons why the itertools implementation is so much more complicated.
Upvotes: 0