Question: 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 corresponding (not related in any computable way).
The code that is now handling the work is:

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

```

Which is IMO quite horrible, and lacks in that both the intervals and the return values are hardcoded.
Any use of any data structure is of course possible.

Answer: 
```
import bisect
bisect.bisect_left([100,300,500,800,1000], p)

```

here the docs: [bisect](https://docs.python.org/3.7/library/bisect.html)
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

```