grouping a flat list of number by range

John Machin sjmachin at lexicon.net
Thu Jun 1 19:35:37 EDT 2006


On 2/06/2006 8:36 AM, Paddy wrote:
> joh12005 at yahoo.fr wrote:
>> hello,
>>
>> i'm looking for a way to have a list of number grouped by consecutive
>> interval, after a search, for example :
>>
>> [3, 6, 7, 8, 12, 13, 15]
>>
>> =>
>>
>> [[3, 4], [6,9], [12, 14], [15, 16]]
>>
>> (6, not following 3, so 3 => [3:4] ; 7, 8 following 6 so 6, 7, 8 =>
>> [6:9], and so on)
>>
>> i was able to to it without generators/yield but i think it could be
>> better with them, may be do you an idea?
>>
>> best regards,
>>
>> J.
> 
> I did a proceedural version, then re-read your post and did a generator
> based version ;-)
> 
> === interv1 ===
>>>> inlist = [3, 6, 7, 8, 12, 13, 15]
>>>> tmp = []
>>>> for i,val in enumerate(inlist):
> ... 	if i==0:
> ... 		tmp.append(val)
> ... 	elif val != valinc:
> ... 		tmp += [valinc, val]
> ... 	valinc = val+1
> ...
>>>> tmp.append(valinc)
>>>> tmp
> [3, 4, 6, 9, 12, 14, 15, 16]
>>>> tmp[0::2]
> [3, 6, 12, 15]
>>>> tmp[1::2]
> [4, 9, 14, 16]
>>>> zip(tmp[0::2], tmp[1::2])
> [(3, 4), (6, 9), (12, 14), (15, 16)]
> 
> === END interv1 ===
> 
> === interv2 ===
>>>> def interv2(inlist):
> ... 	for i,val in enumerate(inlist):
> ... 		if i==0:
> ... 			tmp = val
> ... 		elif val != valinc:
> ... 			yield [tmp, valinc]
> ...                     tmp = val
> ... 		valinc = val+1
> ... 	yield [tmp, valinc]
> ...
>>>> list(interv2(inlist))
> [[3, 4], [6, 9], [12, 14], [15, 16]]
> 
> === END interv2 ===
> 
> - Paddy.
> 

Oh the siren call of every new feature in the language!
enumerate() just to get a first-time test, and then botch it??

Read the following; the replacement version uses a simple old-fashioned 
inelegant flag, works with an empty sequence, and doesn't depend on the 
input being sliceable or indexable.

HTH,
John

C:\junk>type interval.py
def interv2(inlist):
     for i,val in enumerate(inlist):
         if i==0:
             tmp = val
         elif val != valinc:
             yield [tmp, valinc]
             tmp = val
         valinc = val+1
     yield [tmp, valinc]

def interv3(inseq):
     first = True
     for val in inseq:
         if first:
             tmp = val
             first = False
         elif val != valinc:
             yield [tmp, valinc]
             tmp = val
         valinc = val + 1
     if not first:
         yield [tmp, valinc]

tests = [
     [3, 4, 6, 9, 12, 14, 15, 16],
     [3, 3, 3],
     [],
     ]

for func in (interv3, interv2):
     for test in tests:
         print "%s(%s) ->" % (func.__name__, test)
         result = list(func(test))
         print "\t%r" % result

C:\junk>interval.py
interv3([3, 4, 6, 9, 12, 14, 15, 16]) ->
         [[3, 5], [6, 7], [9, 10], [12, 13], [14, 17]]
interv3([3, 3, 3]) ->
         [[3, 4], [3, 4], [3, 4]]
interv3([]) ->
         []
interv2([3, 4, 6, 9, 12, 14, 15, 16]) ->
         [[3, 5], [6, 7], [9, 10], [12, 13], [14, 17]]
interv2([3, 3, 3]) ->
         [[3, 4], [3, 4], [3, 4]]
interv2([]) ->
Traceback (most recent call last):
   File "C:\junk\interval.py", line 33, in ?
     result = list(func(test))
   File "C:\junk\interval.py", line 9, in interv2
     yield [tmp, valinc]
UnboundLocalError: local variable 'tmp' referenced before assignment

C:\junk>



More information about the Python-list mailing list