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

AltStyle によって変換されたページ (->オリジナル) /