Питання Перевірте, чи існує певна клавіша в словнику


Я хотів перевірити, чи існує ключ у словнику перед тим, як оновити значення для ключа. Я написав такий код:

if 'key1' in dict.keys():
  print "blah"
else:
  print "boo"

Я думаю, що це не найкращий спосіб досягти цього завдання. Чи є кращий спосіб перевірити ключ у словнику?


2189
2017-10-21 19:05


походження


Дзвінок dict.keys() створює список ключів відповідно до документації docs.python.org/2/library/stdtypes.html#dict.keys але я був би здивований, якщо цю схему не було оптимізовано для серйозної реалізації, щоб перекласти його if 'key1' in dict:. - Evgeni Sergeev
Тому я нарешті з'ясував, чому багато хто з моїх сценаріїв Python були настільки повільні :) :( Це тому, що я використовував x in dict.keys() перевірити на ключі. І це сталося тому, що звичайним способом повторення клавіш в Java є for (Type k : dict.keySet()), ця природа викликає for k in dict.keys() відчувати себе більш природним, ніж for k in dict (що все ще має бути добре в плані продуктивності?), але потім перевірка ключів стає if k in dict.keys() теж це проблема ... - Evgeni Sergeev
@ ЕвгеніСергеєв if k in dict_: тести на наявність k в ключах dict_, тому вам все одно не потрібно dict_.keys(). (Це трохи в мені, як він читає мені, як його тестування для вартість в дикт. Але це не так.) - ToolmakerSteve
@ToolmakerSteve Це правильно, але не тільки вам це не потрібно, це не найкраща практика. - Evgeni Sergeev
Спробуйте "ввести ключ" - marcelosalloum


Відповіді:


in призначений спосіб перевірити існування ключа в a dict.

d = dict()

for i in xrange(100):
    key = i % 10
    if key in d:
        d[key] += 1
    else:
        d[key] = 1

Якщо ви хочете за замовчуванням, ви завжди можете використовувати dict.get():

d = dict()

for i in xrange(100):
    key = i % 10
    d[key] = d.get(key, 0) + 1

... і якщо ви хочете завжди забезпечувати значення за замовчуванням для будь-якої клавіші, яку ви можете використовувати defaultdict від collections модуль, так:

from collections import defaultdict

d = defaultdict(lambda: 0)

for i in xrange(100):
    d[i % 10] += 1

... але в цілому, in ключове слово - це найкращий спосіб це зробити.


2242
2017-10-21 19:10



Я зазвичай просто використовую get якщо я збираюся все-таки витягувати виріб зі словника. Немає сенсу в користуванні in  і витягніть предмет із словника. - Jason Baker
Я повністю згоден. Але якщо вам потрібно лише знати, чи існує ключ, або вам потрібно розрізнити ситуацію, коли ключ визначено, і випадку, коли ви використовуєте за замовчуванням in це найкращий спосіб це зробити. - Chris B.
Посилання для відповіді на python docs - enkash
отримати - це поганий тест, якщо ключ відповідає "False", наприклад 0 наприклад. Вивчав це важким шляхом: - Sebastien
Я не можу погодитися з тим, що це повна відповідь, оскільки в ньому не згадується, що "спробуй" - "за винятком" буде найшвидшим, коли кількість ключових збігів буде досить невеликою. Див. Цю відповідь нижче: stackoverflow.com/a/1602945/4376643 - Craig Hicks


Вам не потрібно дзвонити клавішам:

if 'key1' in dict:
  print "blah"
else:
  print "boo"

Це буде багато швидше оскільки він використовує хешування словника, на відміну від здійснення лінійного пошуку, який зробить ключі виклику.


1099
2017-10-21 19:06



Це чудово. Мені було враження, що воно всередині ще перетинає список ключів, але я бачу, що це працює, як тестування членства в наборі. - Mohan Gulati
@ Мохан Гулати: Ви розумієте, що словник - це хешбайт клавіш, зіставлених із значеннями, чи не так? Алгоритм хешування перетворює ключ на ціле, а ціле число використовується для пошуку місця в таблиці хешу, яка відповідає. en.wikipedia.org/wiki/Hash_table - hughdbrown
@ Charles Addis, з досвіду роботи з приблизно півмільйонами клавіш ви отримуєте принаймні 10-кратний приріст продуктивності, коли пишете "key in dict" замість "key in dict.keys ()". PEP і Zen також заявляють, що ви повинні ігнорувати їх, якщо вони погані для вашого проекту. - ivan_bilan
ivan_bilan - Я просто керував своїм контролем на це ... На півмільйона ключів, if key in d1 взяв 0.17265701293945312 секунд Дзвінок if key in d1.keys() взяв 0.23871088027954102 - це класичне визначення мікро-оптимізації. Збереження 0.07884883880615234 секунд не є підвищення продуктивності. - Charles Addis
@Eli Просто для вас я створив тест, який можна запустити самостійно. Результати можуть вражати вас. Для диктату з ~ 50 000 клавіш, не дзвонити keys() дає вам .01 другий обчислювальну вигоду. Для ~ 500 000 ключів, не дзвонити keys() дає вам .1 другу користь. Для ~ 5,000,000 ключів, не дзвони keys() швидше, на 4 секунди, але за 50 мільйонів ключів ЗВ'ЯЗКУ keys() IS 3 SECONDS FASTER! - Charles Addis


Ви можете перевірити присутність ключа у словнику, використовуючи в ключове слово:

d = {'a': 1, 'b': 2}
'a' in d # <== evaluates to True
'c' in d # <== evaluates to False

Загальноприйняте використання перевірки існування ключа в словнику перед тим, як його змінити, це за замовчуванням ініціалізувати значення (наприклад, якщо ваші значення є списками, наприклад, і ви хочете переконатися, що є пустий список, до якого ви можете додати при вставці першого значення для однієї клавіші). У таких випадках ви можете знайти collections.defaultdict() тип, що представляє інтерес.

У старшому коді ви також можете знайти деякі способи використання has_key(), застарілий спосіб перевірки наявності ключів у словниках (просто використовуйте key_name in dict_name, замість цього).


226
2017-10-21 19:16



dict.has_key (ключ) застарілий на користь ключа в dict - David Locke
Технічно has_key є не підтримується для Python 2.x + (не тільки для 3.0+). Тобто, новий код рекомендується не використовувати його, навіть під час написання в Python 2.x. (Оскільки ця функція, як відомо, відхиляється в майбутніх версіях, і замість цього є ідеальним замінником.) Що відбувається в 3.0, це те, що вона повністю видаляється. - ToolmakerSteve
@ToolmakerSteve Ви, звичайно, правильні, і я оновив відповідь, щоб відобразити це. :) - kqr
Потрібно поділитися цим (використовуючи Python 2.7) час виконання щось, що я щойно написав, основуючись на dicts, був 363.235070, використовуючи "ключ в dict.keys ()" і різко знизився до 0.260186 виключно шляхом видалення дзвінка на "keys ( ) " - Ido_f
@Ido_f, будь-ласка, опублікуйте свої орієнтири, оскільки мої орієнтири практично не відрізняються в 3.5 і 2.7 - Charles Addis


Ви можете скоротити це:

if 'key1' in dict:
    ...

Однак це, в кращому випадку, косметичне поліпшення. Чому ви вважаєте, що це не найкращий спосіб?


74
2017-10-21 19:06



Це багато чого більше, ніж косметичне покращення. Час, щоб знайти ключ, використовуючи цей метод, є O (1), тоді як клавіші викликів можуть генерувати список і бути O (n). - Jason Baker
О (1) зовсім не здається правильним. Ви впевнені, що це не щось на зразок O (log n)? - spectras
Це складність одиничного пошуку дикту, який в середньому становить O (1) і в гіршому випадку O (n). .list () завжди буде O (n). wiki.python.org/moin/TimeComplexity - Leo Tindall


Я б рекомендував використовувати setdefault метод замість цього. Схоже, що він зробить все, що хочеш.

>>> d = {'foo':'bar'}
>>> q = d.setdefault('foo','baz') #Do not override the existing key
>>> print q #The value takes what was originally in the dictionary
bar
>>> print d
{'foo': 'bar'}
>>> r = d.setdefault('baz',18) #baz was never in the dictionary
>>> print r #Now r has the value supplied above
18
>>> print d #The dictionary's been updated
{'foo': 'bar', 'baz': 18}

40
2017-10-21 19:07



Що робить setdefault пов'язані з питанням ОП? - hughdbrown
@hughdbrown "Я хотів перевірити, чи існує ключ у словнику перед тим, як оновити значення для ключа". Іноді публікації містять код, який створює шквал відповідей на те, що не зовсім початкова мета. Для досягнення мети, зазначеної в першому реченні, setdefault є найефективнішим способом, навіть якщо воно не є відхиленням для показу коду зразка. - David Berger
Це найкраща відповідь, оскільки вона задовольняє мети ОФ, а не лише технічно правильну відповідь. Побачити: nedbatchelder.com/blog/201207/... - Niels Bom
+1 для інформативної відповіді, що навчила мене щось. Однак, чи це найкраще рішення залежить від того, що має на увазі кодер; наприклад, значення "перед оновленням значення ключа". Може бути, він збирається виключити, якщо його немає (== немає дозволу на додавання нових ключів). Може бути, це словник підрахунків, і він збирається додати 1 до існуючого підрахунку, в цьому випадку `d [ключ] = d.get (ключ, 0) + 1 'є найчистішим рішенням (як показує Кріс, після вашої відповіді був написаний). (Я лише намагаюсь згадати це, якщо майбутні читачі приходять сюди з різними завданнями). - ToolmakerSteve
@NielsBom ... IMHO setdefault is тільки в начальник рішення, коли має існувати запис ні бути перезаписаним (Важливою справою, але не єдиною причиною перевірки існування ключа.) - ToolmakerSteve


Для отримання додаткової інформації про швидкість виконання пропонованих методів прийнятої відповіді (10 м циклів):

  • 'key' in mydict минув час 1,07 сек
  • mydict.get('key') пройшло 1,84 сек
  • mydefaultdict['key'] минув час 1,07 сек

Тому використовуючи in або defaultdict рекомендуються проти get.


35
2018-05-29 11:06



отримати по суті поєднання пунктів 1 і 3 куль. - scape
цілком згодні з цим get1,84 секунди <1,07 * 2 ;-P - Paul Rigor


Словник в python має метод get ('key', default). Таким чином, ви можете просто встановити значення за замовчуванням у випадку відсутності ключа.

values = {...}
myValue = values.get('Key', None)

19
2018-03-01 09:03