Удаление всех значений из словаря оптимальным способом - PullRequest
0 голосов
/ 14 декабря 2018

У меня есть словарь типа:

z = {'d': '2018', 'uc': '609', 'bc': 'HSBC', 'ab': 'FICCL', .... }

. В нем 57 пар ключ-значение.Я хочу сохранить ключи, но удалить значения и сделать их пустой строкой, как "".Я пробовал следующий код:

for k,v in z.items():
    z[k] = ""

Я получаю желаемый вывод, например:

z = {'d': '', 'uc': '', 'bc': '', 'ab': '', .... }

Мне было интересно, это самый простой способ удалить все значения сразу в словаре,Есть ли другой путь?Есть ли встроенная функция для этого?Есть ли однострочник без петли?

Ответы [ 6 ]

0 голосов
/ 14 декабря 2018

суммируя и синхронизируя различные опубликованные ответы, они все выглядят примерно одинаковыми во время выполнения.

Я начинаю с создания относительно большого dict:

src = {str(i):i for i in range(1_000_000)}

с использованием dict.fromkeys:

dict.fromkeys(src.keys(), '')

занимает 183 мс ± 11,7 мс.Обратите внимание, что Мохаммед z.fromkeys(z… делает то же самое.

понимание dict:

{k:'' for k in src.keys()}

занимает то же самое в 183 мс ± 5,11 мс.обратите внимание, что iter(src) - это просто сокращение для iter(src.keys()), и я обычно предпочитаю быть явным

, пока мутирует на месте:

for k in src.keys():
    src[k] = ''

немного быстрее на 162мс ± 6,15 мс

0 голосов
/ 14 декабря 2018

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

Вы можете отбросить вызов items(), если вас не интересуют значения.Просто зацикливайтесь прямо над словарем, чтобы получить ключи:

for k in z:
    z[k] = ""

Альтернатива - использовать dict.fromkeys() для создания нового пустого словаря.Чтобы обновить существующий dict на месте (чтобы другие ссылки на тот же словарь увидели изменения), вы можете вызвать z.update(), передавая в новом словаре:

# set all values to an empty string, in place
z.update(dict.fromkeys(z, ""))

Недостатком будетВозможно, вам понадобится добавить комментарий, чтобы объяснить, чего должна достичь эта линия.Это также медленнее , потому что новый объект создается только для обновления существующего объекта.Кроме того, вы хотите осторожно , используя dict.fromkeys(), поскольку вторым аргументом является единственное значение, которое повторно используется для всех ключей.Это имеет значение, если вы должны использовать изменяемое значение, такое как список.Если вам нужен только новый словарь, вы должны набрать z.update() и просто присвоить результат dict.fromkeys() непосредственно z.

Предполагая, что вам нужно обновления на месте , быстрое сравнение различий в производительности:

>>> from timeit import Timer
>>> testdict = {i: i for i in range(10 ** 6)}
>>> def explicit_loop(d):
...     d = d.copy()
...     for k in d:
...         d[k] = ""
...
>>> def dict_fromkeys(d):
...     d = d.copy()
...     d.update(dict.fromkeys(d, ""))
...
>>> def base_copy(d):
...     d = d.copy()
...
>>> count, total = Timer("f(t)", "from __main__ import base_copy as f, testdict as t").autorange()
>>> base_copy_time = total / count
>>> for f in (explicit_loop, dict_fromkeys):
...     count, total = Timer("f(t)", f"from __main__ import {f.__name__} as f, testdict as t").autorange()
...     print(f"{f.__name__:>15}: {((total / count) - base_copy_time) * 1000:.2f} milliseconds")
...
  explicit_loop: 43.15 milliseconds
  dict_fromkeys: 68.66 milliseconds

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

Вы можете видеть, что явный цикл по z явно выиграл.Но даже если вам не необходимо обновить словарь на месте, использование dict.fromkeys() медленнее, чем обновление z на месте!

Обновление на месте ненеобходимо динамически изменять размер словаря, чтобы соответствовать произвольному количеству ключей, и не нужно создавать новый объект:

>>> def dict_fromkeys_no_update(d):
...     d = d.copy()  # to keep comparisons fair, copy only needed for the loop case
...     d = dict.fromkeys(d, "")
...
>>> for f in (explicit_loop, dict_fromkeys_no_update):
...     count, total = Timer("f(t)", f"from __main__ import {f.__name__} as f, testdict as t").autorange()
...     print(f"{f.__name__:>25}: {((total / count) - base_copy_time) * 1000:.2f} milliseconds")
...
            explicit_loop: 41.27 milliseconds
  dict_fromkeys_no_update: 54.78 milliseconds

Итак, нужен ли вам новый словарь или обновление на месте, простопростой цикл Python над существующими ключами словаря является здесь бесспорным победителем.

0 голосов
/ 14 декабря 2018

Вам не нужно .items(), поэтому ваш код может быть упрощен:

for k in z:
    z[k] = ""

Я не думаю, что есть однострочный, который делает то же самое и одинаково эффективен / читабелен,Использовать цикл здесь вполне нормально, IMO (если только нет особой причины, по которой вам нужен один вызов функции).

0 голосов
/ 14 декабря 2018

Метод проверки fromkeys Так что это будет z = z.fromkeys(z, '') Надеюсь, что поможет

0 голосов
/ 14 декабря 2018

Вы можете использовать fromkeys для создания словаря из списка ключей и указать, какими должны быть «пустые» значения.

empty_dict = dict.fromkeys(original_dict.keys(), '')
0 голосов
/ 14 декабря 2018
z = dict.fromkeys(z.keys(), "")
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...