выставление оценок на основе диапазона:
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'
......
Проблема заключается в проверке нужно добавить еще 20, поэтому есть ли способ сделать лучше, чем этот подход.
Верхняя и нижняя границы диапазона всегда будут 2 ^ n?
начните с того, что выбросите все минимальные проверки - они не нужны, как раньше, если бы сработали
@PatrickArtner, безусловно, не может бросить min, так как необходимо также присвоить оценку этому значению
if size < 32: do somthing elif size < 64: do something
и т. д. Если 33, то для 2-го >32 and <=64
проверять не нужно. Если меньше 33, то сработал бы первый. Это примерно сокращает ваши утверждения на 50%, но было бы лучше использовать max-value: label dict
Что сказал @PatrickArtner. Так что вам не нужны все эти двойные тесты. Однако, когда вам делать нужны такие двойные тесты, лучше писать 32 < size <= 64
, чем size > 32 and size <=64
.
@ PM2Ring да, это может устранить немного кода!
Поскольку диапазоны непрерывны, вы можете избежать повторения нижней границы.
Помещение всех диапазонов в кортежи может сэкономить вам немного времени на ввод (если первый диапазон не опускается до отрицательной бесконечности, подумайте о добавлении кортежа (0, None)
перед всеми остальными:
def getGrade(size):
grades = (
(32, 'p4'),
(64, 'p6'),
(128, 'p10'),
...
)
for maxVal, grade in grades:
if size <= maxVal:
return grade
Контрольная работа:
>>> getGrade(45)
'p6'
>>> getGrade(100)
'p10'
Эффективность:
Если список grades
действительно длинный, вы можете добиться лучшего времени выполнения, чем сканирование каждого элемента. Поскольку список отсортирован, вы можете использовать bisect
, заменив цикл for:
for maxVal, grade in grades:
if size <= maxVal:
return grade
с участием:
index = bisect.bisect(grades, (size, ))
if index < len(grades):
return grades[index][1]
Количество шагов сокращается (в худшем случае) с N (длина grades
) до log2 (N).
или просто return next((grade for s, grade in grades if size <= s), None)
?
@hiroprotagonist - это всего одна строка, но она длиннее по количеству токенов. В любом случае проблема длины кода здесь глупая; дело в том, что "многословный" for
более читабелен. (несмотря на то, насколько я фанат одинарных лайнеров)
@fferri, я должен признать: я согласен!
Подход грубой силы был бы прост, как
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]
может потребоваться место, если список экспоненциальный
если диапазоны равны Еще 20, это означает, что самый верхний диапазон равен 2147483648, определенно пустая трата места!
Создать
dict
из объектовrange
(в качестве ключа) и строк оценки (в качестве значения)?