how to efficiently check contiguous ranges in pyth

2019-05-13 18:19发布

问题:

assigning grade on basis of range:

def getGrade(size):
    grade =''
    if size <= 32:
        grade = 'p4'
    elif size > 32 and size <=64:
        grade = 'p6'
    elif size > 64 and size <= 128:
        grade = 'p10'
    elif size > 128 and size <= 256:
        grade = 'p15'
    elif size > 256 and size <=512:
        grade = 'p20'
    elif size > 512 and size <= 1024:
        grade = 'p30'
    elif size > 1024 and size <= 2048:
        grade = 'p40'
    ......

Problem is need to add 20 more check so is there any way to do better than this approach.

回答1:

Due do the ranges being contiguous, you can avoid repeating the lower bound.

Putting all the ranges in tuples can save you some typing (if the first range does not go down to negative infinity, consider adding the tuple (0, None) before all others:

def getGrade(size):
    grades = (
         (32, 'p4'),
         (64, 'p6'),
        (128, 'p10'),
        ...
    )

    for maxVal, grade in grades:
        if size <= maxVal:
            return grade

Test:

>>> getGrade(45)
'p6'
>>> getGrade(100)
'p10'

Efficiency:

If the grades list is really long, you can achieve better runtime than scanning every item. Since the list is sorted, you can use bisect, by replacing the for loop:

    for maxVal, grade in grades:
        if size <= maxVal:
            return grade

with:

    index = bisect.bisect(grades, (size, ))
    if index < len(grades):
        return grades[index][1]

The number of steps is reduced (in the worst case) from N (the length of grades) to log2(N).



回答2:

A brute force approach would be simple as

all_grades = [i for i in chain(repeat('p4',32),repeat('p6',64-32) and so on)]

then you can get grade as

grade = all_grades[size-1]

it may require space if list is exponential