Как изменить все словарные ключи в цикле for с помощью d.items ()?

Я хотел бы помочь с пониманием того, почему этот код работает не так, как ожидалось.

Если вы хотите изменить ключ словаря, но сохраните его значение, он может использовать:

d[new_key] = d.pop[old_key] 

Я хочу изменить все ключи (и сохранить значения на месте), но код ниже пропускает определенные строки – («col2») остается нетронутым. Это потому, что словари неупорядочены, и я продолжаю изменять значения в нем?

Как я могу изменить ключи и сохранить значения без создания нового словаря?

 import time import pprint name_dict = {"col1": 973, "col2": "1452 29th Street", "col3": "Here is a value", "col4" : "Here is another value", "col5" : "NULL", "col6": "Scottsdale", "col7": "N/A", "col8" : "41.5946922", "col9": "Building", "col10" : "Commercial"} for k, v in name_dict.items(): print("This is the key: '%s' and this is the value '%s'\n" % (k, v) ) new_key = input("Please enter a new key: ") name_dict[new_key] = name_dict.pop(k) time.sleep(4) pprint.pprint(name_dict) 

3 Solutions collect form web for “Как изменить все словарные ключи в цикле for с помощью d.items ()?”

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

 name_dict = {1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6} for k, v in name_dict.items(): name_dict.pop(k) 

RuntimeError: словарь изменил размер во время итерации

Однако в вашем случае вы добавляете один элемент для каждого удаленного элемента. Это делает его более свернутым. Чтобы понять, что происходит, вам нужно знать, что словарь несколько напоминает редкую таблицу. Например, такой словарь, как {1: 1, 3: 3, 5: 5} может выглядеть так (это было изменено в Python 3.6, для версии 3.6 и новее следующее неверно):

 hash key value - - - 1 1 1 - - - 3 3 3 - - - 5 5 5 - - - - - - - - - 

Это также порядок, в котором он повторяется. Поэтому на первой итерации он перейдет ко второму пункту (где хранится 1: 1 ). Предположим, вы изменили ключ на 2 и удалили ключ 1 бы выглядел так:

 hash key value - - - - - - 2 2 1 3 3 3 - - - 5 5 5 - - - - - - - - - 

Но мы все еще находимся на второй линии, поэтому следующая итерация будет идти к следующей «непустой» записи, которая равна 2: 1 . Oups …

Это еще сложнее со строками в качестве ключей, потому что хеши-строки рандомизированы (по каждому сеансу), поэтому порядок внутри словаря непредсказуем.

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

Предполагая, что у вас есть этот цикл:

 name_dict = {1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6} for k, v in name_dict.items(): # print(k, k+6, name_dict.__sizeof__()) name_dict[k+6] = name_dict.pop(k) # print(name_dict) 

Первоначальный макет выглядит так:

 key value 1 1 2 2 3 3 4 4 5 5 6 1 

Первая петля удаляет 1 но добавляет 7 . Поскольку словари упорядочены в 3.6, это вставляет местозаполнитель, где 1 был:

 key value - - 2 2 3 3 4 4 5 5 6 1 7 2 

Это продолжается до тех пор, пока вы не замените 4 на 10 .

 key value - - - - - - - - 5 5 6 1 7 2 8 3 9 4 10 5 

Но когда вы замените 5 на 11 словарь должен будет увеличить его размер. Затем происходит что-то особенное: Заполнители удаляются:

 key value 6 6 7 1 8 2 9 3 10 4 11 5 

Итак, мы были в позиции 5 в последней итерации, и теперь мы меняем линию 6. Но строка 6 содержит 11: 5 прямо сейчас. Oups …

Никогда не изменяйте объект, который вы повторяете: не возитесь с клавишами во время итерации (значения в порядке)!

Вместо этого вы можете хранить «таблицу переводов» (не знаю, нарушает ли это ваше требование «без создания нового требования», но вам нужно какое-то хранилище, чтобы ваш код работал правильно) и выполните переименование после цикла:

 translate = {} for k, v in name_dict.items(): print("This is the key: '%s' and this is the value '%s'\n" % (k, v) ) new_key = input("Please enter a new key: ") translate[k] = new_key time.sleep(4) for old, new in translate.items(): name_dict[new] = name_dict.pop(old) 

Чтобы иметь итерируемый объект в вашей рабочей памяти, который не зависит от вашего исходного словаря, вы можете использовать метод из fromkeys . Теперь можно назначить новые ключи старыми значениями. Но есть одна вещь, которую вы должны иметь в виду: вы не можете назначить значение новому ключу, который не является определенным старым ключом, в то время как новый ключ также является еще одним ключом из старого набора ключей.

 Old_Keys = { old_key_1, old_key_2, ..., old_key_n } 

Таким образом, вы назначаете значение, связанное с старым ключом, на новый ключ.

 old_key_1 -> new_key_1 not in Old_Keys # Okay! old_key_2 -> new_key_2 == old_key_4 # Boom!... Error!... 

Помните об этом, когда используете следующее:

КОД

 D = {'key1': 'val1', 'key2': 'val2', 'key3': 'val3'} for key in D.fromkeys(D) : new_key = raw_input("Old Key: %s, New Key: " % key) D[new_key] = D.pop(key) print D 

КОНСОЛЬ

 Old Key: key1, New Key: abc Old Key: key2, New Key: def Old Key: key3, New Key: ghi {"abc": 'val1', "def": 'val2', "ghi": 'val3'} 

в python3 dict.items () – это просто взгляд на dict. так как вам не разрешено изменять итерацию при повторении, вам не разрешается изменять dict, итерации по dict.items (). вам нужно скопировать элементы () в список перед итерацией

 for k, v in list(name_dict.items()): ... name_dict[new_key] = name_dict.pop(k) 

это действительно соответствует вашему требованию «нет нового дикта», хотя этот список содержит фактически полную копию всех ваших данных.

вы можете немного уменьшить объем памяти, скопировав только клавиши

 for k in list(name_dict): v = name_dict.pop(k) ... name_dict[new_key] = v 

EDIT: кредиты Свену Крюгеру, он поднял возможность столкновения с старыми ключами и новыми ключами. в этом случае вам нужно идти

 kv = list(name_dict.items()) name_dict.clear() for k, v in kv : ... name_dict[new_key] = v 

Кстати, есть прецедент для не создания нового dict, на текущий может быть ссылка где-то еще.

  • PyQt5 не удалось импортировать QtGui
  • Неисправность нажатием кнопки для следующей страницы
  • Почему вы можете прокручивать неявный кортеж в цикле for, но не понимать Python?
  • Как удалить запись из таблицы?
  • Преобразование из utf-16 в utf-8 в Python 3
  • Не удается установить pyinstaller с помощью pip
  • Как перенести первую букву слова в конец
  • как устранить проблему «AttributeError: __exit__» в многопроцессорности в Python?
  • Ошибка импорта ctypes Python в virtualenv
  • Как можно изменить синтаксис индексации списка python?
  • Типовой код Matplotlib - превышает ошибку Locator.MAXTICKS без видимых причин
  •  
    Interesting Posts for Van-Lav

    Список как член класса python, почему его содержимое является общим для всех экземпляров класса?

    Попытка запустить KIVY в первый раз

    Может загружать носители Django, не может извлекать

    Создайте список, используя умножение, но не каждое зеркало списка

    Pip.exe из Python в Windows 10

    Поиск строки, допускающей одно несоответствие в любом месте строки

    Устранение ошибки GCC при установке python-ldap на Redhat Enterprise Server

    Как работает эта однострунная конвертация вектора?

    Закрепление неравных списков в python в список, который не отбрасывает ни один элемент из более длинного списка,

    Ошибка: команда «gcc» не выполнена: нет такого файла или каталога

    AttributeError: модуль 'tensorflow.models.embedding.gen_word2vec' не имеет атрибута 'skipgram_word2vec'

    Как работает оператор запятой Python во время назначения?

    Веб-сервер Heroku не начнется локально

    Каков самый быстрый способ создания эскизов изображений в Python?

    Python, как индексировать многомерный массив со строковым ключом, например, dict

    Python - лучший язык программирования в мире.