if number is 1-2, 4 or 6-8 or 12-28, 30, 32...

Cliff Wells logiplexsoftware at earthlink.net
Tue Jun 11 20:15:53 EDT 2002


On Tue, 11 Jun 2002 16:44:08 GMT
Terry Reedy wrote:

> 
> > "Gustaf Liljegren" <gustafl at algonet.se>
> wants elegant function matching int to any of multiple numbers and
> ranges
> 
> My very-pseudo code had parity error at end.  Real Python code:
> 
> import bisect
> 
> # noncontiguous and sorted numbers and ranges: 1, 3, 10-300, 2999,
> 12345-98765
> # expanded to (lo, hi+1) ranges and flattened to list - exercise for
> OP
> rangenums = (1,2, 3,4, 10,301, 2999,3000, 12345,98766)
> 
> for i in (0,1,2, 3,4, 10,20, 300,301, 90000,98765,98766,100000):
>   print bisect.bisect(rangenums, i) %2,
> 
> 0 1 0 1 0 1 1 1 0 1 1 0 0
> >>>

Hm. I haven't used bisect() before:


from bisect import bisect
from time import time
from random import random, randrange, shuffle

class Ranges:
    def __init__(self, ranges):
        self.ranges = []
        self.breakpoints = []
        for r in ranges:
            try:
                s, e = r
            except TypeError:
                s, e = r, r
            self.ranges.append((s, e))
        self.ranges.sort()
        self.breakpoints = map(lambda r: r[0], self.ranges)

    def has(self, n):
        s, e = self.ranges[bisect(self.breakpoints, n) - 1]
        return s <= n <= e

def isin(n, ranges):
    for r in ranges:
        try: 
            s, e = r
            if s <= n <= e:
                return 1
        except TypeError:
            if n == r:
                return 1
    return 0

def createRanges(n):
    # create a list of non-overlapping sequences and ints, there's probably a
faster way...
    ranges = []
    s = 0
    for i in range(n):
        l = int(random() * 1000) + 1
        e = s + l
        s = randrange(s, e)
        if int(random() * 10) % 2:
            ranges.append((s, e))
        else:
            ranges.append(s)
        s = e
        e += l
        
    shuffle(ranges)
    return ranges


# ------------
ranges = createRanges(10000)

print "Initialize Range:",
t1 = time()
r = Ranges(ranges)
print time() - t1

t2 = time()
print "Range():",
for i in range(0, 100, 3):
    r.has(i)
t = time()
print t - t2, "total", t - t1

t = time()
print "isin():",
for i in range(0, 100, 3):
    isin(i, ranges)
print time() - t


####################################
Initialize Range: 0.331060051918
Range(): 0.00136804580688 total 0.33601808548
isin(): 4.98800003529

Clearly faster although it does use a bit more memory...

-- 
Cliff Wells, Software Engineer
Logiplex Corporation (www.logiplex.net)
(503) 978-6726 x308  (800) 735-0555 x308





More information about the Python-list mailing list