LINUX.ORG.RU

Чем заменить многократные elif

 , ,


2

3

Шалом.

Сабж, собственно. Изучаю python и хочу узнать, можно ли более красиво и правильно сделать сие:

if  p7 >= 12 and p7 <= 33:
    p8="ССВ"
elif  p7 >= 34 and p7 <= 56:
    p8="СВ"
elif  p7 >= 57 and p7 <= 78:
    p8="ВСВ"
elif  p7 >= 79 and p7 <= 101:
    p8="В"
elif  p7 >= 102 and p7 <= 123:
    p8="ВЮВ"
elif  p7 >= 124 and p7 <= 146:
    p8="ЮВ"
elif  p7 >= 147 and p7 <= 168:
    p8="ЮЮВ"
elif  p7 >= 169 and p7 <= 191:
    p8="Ю"
elif  p7 >= 192 and p7 <= 213:
    p8="ЮЮЗ"
elif  p7 >= 214 and p7 <= 236:
    p8="ЮЗ"
elif  p7 >= 237 and p7 <= 258:
    p8="ЗЮЗ"
elif  p7 >= 259 and p7 <= 281:
    p8="З"
elif  p7 >= 282 and p7 <= 303:
    p8="ЗСЗ"
elif  p7 >= 304 and p7 <= 326:
    p8="СЗ"
elif  p7 >= 327 and p7 <= 348:
    p8="ССЗ"
elif  p7 >= 349 and p7 <= 360:
    p8="С"
elif  p7 >= 0 and p7 <= 11:
    p8="С"
else:
    p8="???"

Заранее благодарю за ответ.
//Вышеприведенное переводит градусы в направление ветра.

★★★★★

Структуру - нижняя граница, верхняя, название в массив и циклом по массиву проверку. Могет питон такое?

ilovewindows ★★★★★
()
Ответ на: комментарий от Legioner

в общем случае рекомендация верная, но в данном случае это будет преждевременной оптимизацией. вариантов не так много и пройти их циклом не составит большого труда

eternal_sorrow ★★★★★
()
Ответ на: комментарий от grem
if a in range

зачем это? у нас a гарантированно int? даже если да, всё равно протое сравнение как в ОП будет быстрее и понятнее чем создание объекта range и проход по его значениям со сравнением каждого значения с a

eternal_sorrow ★★★★★
()
Ответ на: комментарий от eternal_sorrow

И на одном уровне с for добавить else, для реализации того, что будет, если внутри цикла ни одно условие не выполнится

for v in values:  
    if v[0] <= p7 <= v[1]:  
        p8 = v[2]
        break
else:
    p8 = ???
grem ★★★★★
()
Последнее исправление: grem (всего исправлений: 2)

Не хватает вариантов с полюсами

grem ★★★★★
()
Ответ на: комментарий от grem

можно просто перед циклом назначить p8 дефолтное значение. но так тоже пойдёт, а семантически даже правильнее. но может затруднить понимание кода для незнакомых с этой конструкцией людей, как мне сейчас

eternal_sorrow ★★★★★
()
Ответ на: комментарий от eternal_sorrow

Сам на прошлой недели о ней узнал, тогда и пригодилась.

Комментарий о том, как это работает я при этом оставил

grem ★★★★★
()
Последнее исправление: grem (всего исправлений: 2)
if p7 < 0 or p7 > 360:
    p8 = "???"
else:
    p8 = [
        "С", "ССВ", "СВ", "ВСВ", "В", "ВЮВ", "ЮВ", "ЮЮВ", 
        "Ю", "ЮЮЗ", "ЮЗ", "ЗЮЗ", "З", "ЗСЗ", "СЗ", "ССЗ",
    ][int((p7 + 11) % 360 / 22.5)]
Deleted
()

Советую Паскаль. Там всё просто:

case (p7) of
12..33: p8 := 'ССВ';
34..56: p8 := 'СВ';
57..78: p8 := 'ВСВ';
79..101: p8 := 'В';
...
end;

saahriktu ★★★★★
()
p8 = (p7 >= 12 and p7 <= 33) and "ССВ" or
     (p7 >= 34 and p7 <= 56) and "СВ" or
     (p7 >= 57 and p7 <= 78) and "ВСВ" or
     (p7 >= 79 and p7 <= 101) and "В" or
     (p7 >= 102 and p7 <= 123) and "ВЮВ" or
        ... or "???"

Не любят на лоре такое, но всё-таки, если от кучи условий по указанным выше советам не избавиться, то вот так в функциональном стиле, сначала может и непривычно, но ориентироваться проще чем в ветках elif.

vvn_black ★★★★★
()

Всего 16 направлений. Таблица из 16 названий направлений. 360/16=22.5 град на направление или +/-11.25.

Набросок

table = ['с','ссв',...,' ссз'] # по часовой стрелке
angle = angle+11.25
if angle > 360
    angle = angle - 360
index = int(angle / 22.5) # целая часть, не округление к ближайшему
table[index] # результат здесь
anonymous
()

Анонимус как всегда лучший. В первом коменте сказали про бисект, а вы все равно глину месите.

Вот как с бисектом делается:

>>> a = [11, 33, 56, 78]
>>> degrees = [11, 33, 56, 78]
>>> names = ["SSV", "SV", "VSV", "V"]
>>> names[bisect.bisect_right(a, 13)]
'SV'
>>> names[bisect.bisect_right(a, 57)]
'V'
>>> 

Уловил идею?

anonymous
()
Ответ на: комментарий от anonymous

Ну. т.е. если убрать лишнее

>>> degrees = [11, 33, 56, 78]
>>> names = ["SSV", "SV", "VSV", "V"]
>>> names[bisect.bisect_right(degrees, 57)]
'V'
>>> names[bisect.bisect_right(degrees, 13)]
'SV'
>>>

Недостающие цифры и буквы сам добавишь

anonymous
()
Ответ на: комментарий от eternal_sorrow

Так и сделал, вот что примерно вышло:

a=60
MyCount=0

WindDirection={0:['ССВ', 12, 33], 1:['СВ', 34,56], 2:['ВСВ',57,78]}

while not (a >= WindDirection[MyCount][1] and a <= WindDirection[MyCount][2]):
	MyCount+=1
else:
	print(WindDirection[MyCount][0])

IPR ★★★★★
() автор топика
Ответ на: комментарий от eternal_sorrow

+1 за дефолтное значение, это куда как более распространённая и ожидаемая практика.

EXL ★★★★★
()
Ответ на: комментарий от anonymous

Ты был близок, но

FULL_CIRCLE = 360
DIRECTIONS = [
    "С", "ССВ", "СВ", "ВСВ",
    "В", "ВЮВ", "ЮВ", "ЮЮВ",
    "Ю", "ЮЮЗ", "ЮЗ", "ЗЮЗ",
    "З", "ЗСЗ", "СЗ", "ССЗ", 
]


def angle_to_wind(angle):
    sector = FULL_CIRCLE / len(DIRECTIONS)
    angle = angle % FULL_CIRCLE + sector / 2

    return DIRECTIONS[angle // sector]

UPD: сам тоже хорош, север не туда поставил.

beresk_let ★★★★★
()
Последнее исправление: beresk_let (всего исправлений: 2)
Ответ на: комментарий от grem

Фортран просто много использовался разными математиками. А Паскаль создан профессором Никлаусом Виртом, которого наградили премией имени Тьюринга именно за создание Паскаля. Паскаль рулит.

saahriktu ★★★★★
()
Ответ на: комментарий от saahriktu

Джон Бэкус (англ. John Warner Backus[1]; 3 декабря 1924 года — 17 марта 2007 года) — американский учёный в области информатики, руководитель команды создателей первого высокоуровневого языка программирования Фортран, изобретатель формы Бэкуса — Наура — одной из самых распространённых и универсальных нотаций для определения синтаксиса формальных языков, лауреат премии Тьюринга (1977).

Награда: За его глубокий, продолжительный и оказавший большое влияние вклад в проектирование практических высокоуровневых программных систем, в частности за его работу над языком Фортран, и его оригинальную публикацию по формализации спецификаций языков программирования

grem ★★★★★
()
Последнее исправление: grem (всего исправлений: 1)
Ответ на: комментарий от beresk_let

Ругнётся на выход за границы списка, потому что код может сделать angle больше FULL_CIRCLE. И ругнётся в третьепитоне, потому что пытаешься индексировать список числом с плавающей точкой.

IMHO, лучше всё на 4 умножить, и работать исключительно в целых числах.

i-rinat ★★★★★
()
Последнее исправление: i-rinat (всего исправлений: 1)
Ответ на: комментарий от i-rinat

Почитай код внимательнее, обе претензии мимо.

UPD: По поводу границ ты прав, а я поспешил. Надо было так:

angle = (angle + sector / 2) % FULL_CIRCLE

beresk_let ★★★★★
()
Последнее исправление: beresk_let (всего исправлений: 2)
Ответ на: комментарий от beresk_let

Почитал.

$ python2.7
Python 2.7.16+ (default, Jul  8 2019, 09:45:29) 
[GCC 8.3.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> FULL_CIRCLE = 360
>>> DIRECTIONS = [
...     "С", "ССВ", "СВ", "ВСВ",
...     "В", "ВЮВ", "ЮВ", "ЮЮВ",
...     "Ю", "ЮЮЗ", "ЮЗ", "ЗЮЗ",
...     "З", "ЗСЗ", "СЗ", "ССЗ", 
... ]
>>> def angle_to_wind(angle):
...     sector = FULL_CIRCLE / len(DIRECTIONS)
...     angle = angle % FULL_CIRCLE + sector / 2
...     return DIRECTIONS[angle // sector]
... 
>>> angle_to_wind(349)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in angle_to_wind
IndexError: list index out of range
>>> 
$ python3
Python 3.7.4 (default, Jul 11 2019, 10:43:21) 
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> FULL_CIRCLE = 360
>>> DIRECTIONS = [
...     "С", "ССВ", "СВ", "ВСВ",
...     "В", "ВЮВ", "ЮВ", "ЮЮВ",
...     "Ю", "ЮЮЗ", "ЮЗ", "ЗЮЗ",
...     "З", "ЗСЗ", "СЗ", "ССЗ", 
... ]
>>> def angle_to_wind(angle):
...     sector = FULL_CIRCLE / len(DIRECTIONS)
...     angle = angle % FULL_CIRCLE + sector / 2
...     return DIRECTIONS[angle // sector]
... 
>>> angle_to_wind(349)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in angle_to_wind
TypeError: list indices must be integers or slices, not float
>>> 

Проверил. Я думаю, что претензии обоснованы: в коде есть дефекты.

i-rinat ★★★★★
()
Ответ на: комментарий от Shadow

Да чё там нечитаемо? Словарь, в словаре каждый элемент - список. По счетчику добираемся до нужного условия и вываливаем первый элемент текущего списка. Без всяких рассчетов и т.д.

IPR ★★★★★
() автор топика

Кстати, ещё автору темы можно посоветовать Ruby:

case p7
when 12..33 then p8="ССВ"
when 34..56 then p8="СВ"
when 57..78 then p8="ВСВ"
when 79..101 then p8="В"
...
else p8="???"
end

saahriktu ★★★★★
()
Последнее исправление: saahriktu (всего исправлений: 1)
sub angle2wind {
    qw(N NNE NE ENE E ESE SE SSE S SSW SW WSW W WNW NW NNW)
    [(11.25 + pop) % 360 / 22.5]
}

print angle2wind(328);

точность как и у тебя.

Deleted
()
Последнее исправление: Deleted (всего исправлений: 1)
Ответ на: комментарий от grem

Где в Фортране, например, возможности для работы с юникодом без плясок со всякими параметрами и прочим? А в Паскале полный набор. UnicodeString, UTF8String(), {$codepage UTF8} (после чего _классические_ строковые функции наподобие copy() начинают корректно работать с юникодными строками),... и т.д.

Что же касается Фортрана:

Modern Fortran language standards have no intrinsic support for Unicode I/O. To bypass this limitation, the Universal Coded Character Set defined in ISO 10646 can be used instead, which is mostly identical to UTF-32.

Люди на Фортране городят такие костыли как, например, эти:

program unicode
    use, intrinsic :: iso_fortran_env
    implicit none
    integer, parameter :: u = selected_char_kind('ISO_10646')
    character(kind=u, len=:), allocatable :: string

    string = u_'unicode character: \u2593'

    open (output_unit, encoding='utf-8')
    print '(a)', string
end program unicode

saahriktu ★★★★★
()
Последнее исправление: saahriktu (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.