Python: Mapping from intervals to values

前端 未结 6 935
遥遥无期
遥遥无期 2020-11-30 00:58

I\'m refactoring a function that, given a series of endpoints that implicitly define intervals, checks if a number is included in the interval, and then return a correspondi

相关标签:
6条回答
  • 2020-11-30 01:14
    import bisect
    bisect.bisect_left([100,300,500,800,1000], p)
    

    here the docs: bisect

    0 讨论(0)
  • 2020-11-30 01:18

    You could try a take on this:

    def check_mapping(p):
        mapping = [(100, 0), (300, 1), (500, 2)] # Add all your values and returns here
    
        for check, value in mapping:
            if p <= check:
                return value
    
    print check_mapping(12)
    print check_mapping(101)
    print check_mapping(303)
    

    produces:

    0
    1
    2
    

    As always in Python, there will be any better ways to do it.

    0 讨论(0)
  • 2020-11-30 01:18

    Another way ...

    def which(lst, p): 
        return len([1 for el in lst if p > el])
    
    lst = [100, 300, 500, 800, 1000]
    which(lst, 2)
    which(lst, 101)
    which(lst, 1001)
    
    0 讨论(0)
  • def which_interval(endpoints, number):
        for n, endpoint in enumerate(endpoints):
            if number <= endpoint:
                return n
            previous = endpoint
        return n + 1
    

    Pass your endpoints as a list in endpoints, like this:

    which_interval([100, 300, 500, 800, 1000], 5)
    

    Edit:

    The above is a linear search. Glenn Maynard's answer will have better performance, since it uses a bisection algorithm.

    0 讨论(0)
  • 2020-11-30 01:34

    Try something along the lines of:

    d = {(None,100): 0, 
        (100,200): 1,
        ...
        (1000, None): 5}
    value = 300 # example value
    for k,v in d.items():
        if (k[0] is None or value > k[0]) and (k[1] is None or value <= k[1]):
            return v
    
    0 讨论(0)
  • 2020-11-30 01:37

    It is indeed quite horrible. Without a requirement to have no hardcoding, it should have been written like this:

    if p <= 100:
        return 0
    elif p <= 300:
        return 1
    elif p <= 500:
        return 2
    elif p <= 800:
        return 3
    elif p <= 1000:
        return 4
    else:
        return 5
    

    Here are examples of creating a lookup function, both linear and using binary search, with the no-hardcodings requirement fulfilled, and a couple of sanity checks on the two tables:

    def make_linear_lookup(keys, values):
        assert sorted(keys) == keys
        assert len(values) == len(keys) + 1
        def f(query):
            return values[sum(1 for key in keys if query > key)]
        return f
    
    import bisect
    def make_bisect_lookup(keys, values):
        assert sorted(keys) == keys
        assert len(values) == len(keys) + 1
        def f(query):
            return values[bisect.bisect_left(keys, query)]
        return f
    
    0 讨论(0)
提交回复
热议问题