#python #dictionary #math
#python #словарь #математика
Вопрос:
Я пытаюсь использовать словарь для разделения его элементов, чтобы получить значение. Если это значение соответствует моим критериям, я хочу остановиться. Мне удалось заставить это работать, но я чувствую, что должен быть более короткий путь. Если у вас есть какие-либо предложения или советы, я был бы признателен.
dict1 = {1:123, 2:220, 3:290, 4:300, 5:329}
prev = 1
prev_key = 1
for key,value in dict1.items():
z = prev/value
if z >= 0.95 and z<= 1.05:
print("key is",prev_key)
break
prev = value
prev_key = key
В этом случае ответом будет prev_key = 3. Заранее спасибо 🙂
Комментарии:
1. Запуск вашего кода никогда не входит в предложение if.
2. Обратите внимание, что в зависимости от версии python словарь может не иметь уникального порядка итераций.
3. @Darina извините, да, я обновил его до 3: 290. мой плохой
4. @tobias_k делает хороший вывод. Первым шагом должно быть преобразование словаря в два списка и, возможно, сортировка.
5. Я работаю на python 3.6 Чего я добиваюсь, преобразуя его в списки?
Ответ №1:
Во-первых, как упоминалось в комментариях, словари не имеют надежного порядка итераций в старых версиях python. Я бы сделал следующее
# convert dictionary to list of key/value tuple pairs
l = [(k, v) for (k, v) in dict1.items())
# iterate over the list of tuples, using zip to get the previous and current value at once
for tup1, tup2 in zip(l, l[1:]):
z = t1[1] / t2[1]
if 0.95 <= z <= 1.05:
print('key is', t1[0])
break
Словари упорядочены по вставке в Python 3.6, так что все должно быть в порядке. Но если вам нужно сначала отсортировать список по значению ключа (выглядит так в вашем MWE), вы можете сделать l = sorted(l, key = lambda x: x[0])
— это сортирует список по первому значению кортежей. Если вы полагаетесь на порядок ключей словаря для своего кода, вам следует использовать OrderedDict
.
Комментарии:
1. Забыл об
prev
инициализации — это может быть достигнуто добавлениемl = [(1,1)]
к списку.
Ответ №2:
Вы могли бы сделать его немного короче (и, ИМХО, более читаемым), (а) используя цепочку сравнения (что также означает, что вам не нужно z
) и (б) выполняя несколько назначений объектов, которые принадлежат друг другу в одной строке:
dict1 = {1:123, 2:220, 3:290, 4:300, 5:329}
prev = prev_key = 1
for key,value in dict1.items():
if 0.95 <= prev/value <= 1.05:
print("key is", prev_key)
break
prev, prev_key = value, key
Для более агрессивного сокращения вы могли бы использовать next
вместо цикла и прерывания и использовать zip(*[iter(...)]*2)
рецепт для итерации пар значений; обратите внимание, однако, что это плохо сочетается с инициализацией prev
с 1
помощью ; вы бы предпочли иметь первую запись 1: 1
в самом dict .
print("key is", next(prev_key for (prev_key, prev), (key, value) in zip(*[iter(dict1.items())]*2)
if 0.95 <= prev/value <= 1.05))
Однако, на мой взгляд, первая (более длинная) версия намного более удобочитаема.
Или разверните dict1.values()
в список вместе с (1, 1)
, а затем zip
с самим собой, смещенным на единицу. Вместе с более короткими именами переменных это тоже вполне читаемо.
lst = [(1, 1), *dict1.items()]
print("key is", next(k1 for (k1, v1), (k2, v2) in zip(lst, lst[1:])
if 0.95 <= v1/v2 <= 1.05))
Беспокоить версии с next
вызовет исключение, если такой элемент не найден. вы можете, например, использовать next((...), default=None)
для противодействия этому.