Найти значение в словаре, соответствующее условию - PullRequest
0 голосов
/ 11 мая 2018

Я пытаюсь установить значение из dict, если условие выполнено. По сути, я перебираю значения моего словаря и проверяю, соответствуют ли они моему условию (затем я перерываю цикл, что не является наилучшей практикой, но сохраняет некоторые итерации)

Вот код, который я использую:

for (key,value) in zip(mn_zone_dict.keys(), mn_zone_dict.values()):
    if cost < value:
        zone = key
        break

Я выполняю свою работу, но она относительно медленная, хотя мне приходится проверять> 10 тыс. Записей, поэтому я ищу какой-то более умный (и, возможно, более питонический) способ решения этой задачи. Я видел функцию any (), но она возвращается, только если есть такая запись, которая соответствует условиям, не сообщая, какая.

Буду рад услышать ваши идеи и предложения.

Ответы [ 3 ]

0 голосов
/ 11 мая 2018

Вы можете сделать это так:

for k in my_zon_dict.keys():
   if cost < my_zon_dict[k]:
      zone = k
      break
0 голосов
/ 11 мая 2018

Если у вас есть данные как есть, только со структурой словаря, вам придется каждый раз повторять их.Наилучшее ускорение, которое вы можете получить, - это использовать понимание вместо цикла, и dict.items вместо zip:

zones = [k for k, v in my_zone_dict.items() if cost < v]

С одной стороны, это повторяет весь dict.С другой стороны, он сразу сообщает вам, сколько значений соответствовало критерию, если таковые имеются.

Проблема здесь в том, что независимо от того, сколько накладных расходов меньше, чем у явного цикла, это все равно O(n) длякаждый поиск.Правильным решением является использование другой или дополнительной структуры данных.Поскольку вы хотите, чтобы value был больше, чем что-либо, я бы порекомендовал max-heap.

Python реализует кучи в модуле heapq.Это немного необычно, потому что он не предоставляет объект кучи, а просто функции для кучи и поддержания списков в виде кучи.Кроме того, поддерживаются только минимальные кучи, но это нормально, потому что вы всегда можете просто отменить свои значения:

my_zone_list = [(-v, k) for k, v in my_zone_dict.items()]
heapq.heapify(my_zone_list)

Это одноразовый штраф O(n), который вам никогда не придется повторять.Весь ваш цикл теперь становится O(1) операцией:

if cost < -my_zone_list[0][0]:
    zone = my_zone_list[0][1]

Вставка новых элементов имеет O(log(n)) стоимость:

heapq.heappush(my_zone_list, (-new_value, new_key))

В качестве примечания, если вы не можете ввестиновые структуры данных, вы могли бы получить лучшую производительность с

v, zone = max((v, k) for k, v in my_zone_dict.items())
if cost < v: ...
0 голосов
/ 11 мая 2018

Вместо итерации объекта zip вы можете выполнять итерацию непосредственно по dict.items:

for k, v in my_zon_dict.items():
    if cost < v:
        zone = k
        break

Это будет более эффективно, чем создание настраиваемой итерируемой молнии.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...