how to group by function if one of the group has relationship with another one in the group?
Peter Otten
__peter__ at web.de
Tue Jul 25 04:59:43 EDT 2017
Ho Yeung Lee wrote:
> from itertools import groupby
>
> testing1 = [(1,1),(2,3),(2,4),(3,5),(3,6),(4,6)]
> def isneighborlocation(lo1, lo2):
> if abs(lo1[0] - lo2[0]) == 1 or lo1[1] == lo2[1]:
> return 1
> elif abs(lo1[1] - lo2[1]) == 1 or lo1[0] == lo2[0]:
> return 1
> else:
> return 0
>
> groupda = groupby(testing1, isneighborlocation)
> for key, group1 in groupda:
> print key
> for thing in group1:
> print thing
>
> expect output 3 group
> group1 [(1,1)]
> group2 [(2,3),(2,4]
> group3 [(3,5),(3,6),(4,6)]
groupby() calculates the key value from the current item only, so there's no
"natural" way to apply it to your problem.
Possible workarounds are to feed it pairs of neighbouring items (think
zip()) or a stateful key function. Below is an example of the latter:
$ cat sequential_group_class.py
from itertools import groupby
missing = object()
class PairKey:
def __init__(self, continued):
self.prev = missing
self.continued = continued
self.key = False
def __call__(self, item):
if self.prev is not missing and not self.continued(self.prev, item):
self.key = not self.key
self.prev = item
return self.key
def isneighborlocation(lo1, lo2):
x1, y1 = lo1
x2, y2 = lo2
dx = x1 - x2
dy = y1 - y2
return dx*dx + dy*dy <= 1
items = [(1,1),(2,3),(2,4),(3,5),(3,6),(4,6)]
for key, group in groupby(items, key=PairKey(isneighborlocation)):
print key, list(group)
$ python sequential_group_class.py
False [(1, 1)]
True [(2, 3), (2, 4)]
False [(3, 5), (3, 6), (4, 6)]
More information about the Python-list
mailing list