简体   繁体   中英

Changing Elif Statement to "Python-Like" Code

I have the understanding that Python is all about efficiency. How would I write the code below to be more Pythonic?

I thought of using a dictionary, but since the conditions for the elif statement are ranges, I don't think that's possible.

threshold_scale
if pop in range(threshold_scale[0], threshold_scale[1]):
    color = '#ff0000'
elif pop in range(threshold_scale[1], threshold_scale[2]):
    color = '#f6ff00'
elif pop in range(threshold_scale[2], threshold_scale[3]):
    color = '#00ff08'
elif pop in range(threshold_scale[3], threshold_scale[4]):
    color = '#0d00ff'
elif pop in range(threshold_scale[4], threshold_scale[5]+1):
    color = '#ff00f7'

Output

[1960, 648065, 1294170, 1940275, 2586380, 3232486]

An interval tree is designed for these types of queries. One example is the intervaltree module.

from intervaltree import IntervalTree, Interval

threshold_scale = [1960, 648065, 1294170, 1940275, 2586380, 3232486]

ranges = zip(threshold_scale, threshold_scale[1:])
colors = ["#ff0000", "#f6ff00", "$00ff08", "$0d00ff", "$ff00f7"]

t = IntervalTree([Interval(x, y, c) for (x,y), c in zip(ranges, colors)])

pop = 2000

color = sorted(t[2000])[0].data

For n intervals, it takes O(n lg n) to build the interval tree, and a single query takes O(lg n) time. (Technically, it's O(lg n + m) , where m is the number of items in the result. Our tree consists of non-overlapping ranges, though, so m always equals 1.)

By comparison, your if statement would take O(n) time. Each pop in range(...) takes O(1) time, but there could be O(n) of them. Using an interval tree is faster if you need to make many queries against the same set of intervals.

colors = [
    '#ff0000',
    '#f6ff00',
    '#00ff08',
    '#0d00ff',
    '#ff00f7',
]
color = next(c for c, t_range in
             zip(colors, zip(threshold_scale, threshold_scale[1:])) if
             pop in range(*t_range))

Given input:

threshold_scale = [0,2,4,6,8,10]
pop = 7

Outputs:

f6ff00

You can use numpy.digitize

import numpy as np

threshold_scale = [1960, 648065, 1294170, 1940275, 2586380, 3232486]

pop = [2000, 2000000, 2800000]

color = np.array(['#ff0000', '#f6ff00', '#00ff08', '#0d00ff', '#ff00f7'])

color[np.digitize(pop, threshold_scale) - 1]

You will have to deal with pop values outside of covered range too...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM