Home > Software engineering >  Is possible to convert multiple if <n in interval> into an array?
Is possible to convert multiple if <n in interval> into an array?

Time:06-24

Code like this

def IsEven(n):
    if n%2==0:
        return "Is even"
    else:
        return "Is odd"

can be converted to a function like this

def isEven(n):
    return ["Is even","Is odd"][n%2==0]

The question is if code like this:

def intervalsToOutput(n):
    intervals=[(x1,x2), (x3,x4), (x5,x6), ... (xn,xn 1)]
    if x1<=n<=x2:
        return "in first interval"
    elif x3<=n<=x4:
        return "in second interval"
    elif x5<=n<=x6:
        return "in third interval"
    ...
    elif xn<=n<=xn 1:
        return "in last interval"

... can be replaced efficiently with a function like this:
(assuming the intervals (xi,xi 1) are not overlapping, and are sorted by xi)

def intervalsToOutput(n):
    intervals=[(x1,x2), (x3,x4), (x5,x6), ... (xn,xn 1)]
    answer=["in first interval","in second interval","in third interval",...,"in last interval"]
    retrurn answer[index of (n in Interval)]
    

The best I made (looking for speed) is

def intervalsToOutput(n):
    intervals=[(x1,x2), (x3,x4), (x5,x6), ... (xn,xn 1)]
    answer=["in first interval","in second interval","in third interval",...,"in last interval"]
    import bisect as bisect
    return answer[bisect.bisect_left(intervals, (n, )) - 1]# -1 because it is a zero based list

What bisect_left does is to find the position of n in intervals (in O(log(n)) time) by comparing (n,) with (xn,xn 1) But the purpose of bisect is to find the insertion place, so it fails for any n which is x_{i 1}<n<=x_{j}

... (x_i, x_{i 1}), (x_j, x_{j 1}) ...
[x_i______x_i 1] fails on this interval x_j [________x_j 1]

CodePudding user response:

Are the intervals random? i.e. if the range is 0-10 and each there are 5 intervals (0-2)(2-4)(4-6)(6-8)(8-10)

Just do something like

def func(n):
    spacing = 2
    return n // 2

CodePudding user response:

I would do this:

intervals=[(1,2),(6,8),(22,45),(101,110)]

tgt=27
idx=next(i for i,t in enumerate(intervals) if t[0]<=tgt<=t[1])

>>> idx
2

If you want to catch a not-found condition, either use try / except:

try:
   idx=next(i for i,t in enumerate(intervals) if t[0]<=tgt<=t[1])
except StopIteration:
    # not found

Or use the default form of next:

idx=next((i for i,t in enumerate(intervals) if t[0]<=tgt<=t[1]), None)

CodePudding user response:

Well here's one way, but don't do this (for readability, and probably performance). You should really just chain if,elif,andelse statements (or use a for loop):

def really_esoteric(n):
    return ["first", "second", "n"][
        [n in range(0,10),
         n in range(11,16),
         n in range(16,30)].index(True)
        ]

REPL:

>>> really_esoteric(5)
'first'
>>> really_esoteric(13)
'second'
>>> really_esoteric(20)
'n'

  • Related