如何使用 d.items() 更改 for 循环中的所有字典键? [英] How to change all the dictionary keys in a for loop with d.items()?

查看:20
本文介绍了如何使用 d.items() 更改 for 循环中的所有字典键?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要一些帮助来理解为什么这段代码没有按预期工作.

如果想改变字典的键但保留值,他/她可能会使用:

d[new_key] = d.pop[old_key]

我想修改所有键(并保留值),但下面的代码跳过了某些行 - (col2")保持不变.是不是因为字典是无序的,我一直在改变里面的值?

如何在不创建新字典的情况下更改键并保留值?

导入时间导入打印name_dict = {"col1": 973, "col2": "1452 29th Street","col3": "这是一个值", "col4": "这是另一个值",col5":NULL",col6":斯科茨代尔",col7":不适用",col8":41.5946922",col9":建筑",col10":商业"}对于 name_dict.items() 中的 k, v:print("这是关键:'%s',这是值'%s'
" % (k, v) )new_key = input("请输入新密钥:")name_dict[new_key] = name_dict.pop(k)时间.sleep(4)pprint.pprint(name_dict)

解决方案

改变你正在迭代的对象从来都不是一个好主意.通常 dict 甚至会在您尝试时抛出异常:

name_dict = {1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6}对于 name_dict.items() 中的 k, v:name_dict.pop(k)

<块引用>

RuntimeError: 字典在迭代过程中改变了大小

但是在您的情况下,您为每个删除的项目添加一个项目.这使得它更加复杂.要了解正在发生的事情,您需要知道字典有点像稀疏表.例如像 {1: 1, 3: 3, 5: 5} 这样的字典可能看起来像这样(这在 Python 3.6 中发生了变化,对于 3.6 和更高版本,以下内容不再正确):

哈希键值- - -1 1 1- - -3 3 3- - -5 5 5- - -- - -- - -

这也是迭代的顺序.因此,在第一次迭代中,它将转到第二项(存储 1:1 的位置).假设您将键更改为 2 并删除键 1 字典将如下所示:

哈希键值- - -- - -2 2 13 3 3- - -5 5 5- - -- - -- - -

但是我们仍然在第二行,所以下一次迭代它将转到下一个非空"条目,即2:1.哎呀……

使用字符串作为键更加复杂,因为字符串哈希是随机的(基于每个会话),因此字典中的顺序是不可预测的.

在 3.6 中,内部布局略有变化,但这里发生了类似的事情.

假设你有这个循环:

name_dict = {1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6}对于 name_dict.items() 中的 k, v:# 打印(k, k+6, name_dict.__sizeof__())name_dict[k+6] = name_dict.pop(k)# 打印(name_dict)

初始布局是这样的:

键值1 12 23 34 45 56 1

第一个循环删除了 1 但添加了 7.因为字典是在 3.6 中排序的,这会在 1 所在的位置插入一个占位符:

键值- -2 23 34 45 56 17 2

这种情况一直持续到您将 4 替换为 10.

键值- -- -- -- -5 56 17 28 39 410 5

但是当你用 11 替换 5 时,字典需要增加它的大小.然后发生了一些特殊的事情:占位符被删除:

键值6 67 18 29 310 411 5

因此,我们在上次迭代中位于第 5 行,现在我们更改第 6 行.但第 6 行现在包含 11: 5.哎呀...

永远不要改变你正在迭代的对象:不要在迭代过程中弄乱键(值没问题)!

您可以改为保留一个翻译表"(不知道这是否违反了您的不创建新字典"的要求,但您需要某种存储才能使您的代码正常工作)并在循环后进行重命名:

translate = {}对于 name_dict.items() 中的 k, v:print("这是关键:'%s',这是值'%s'
" % (k, v) )new_key = input("请输入新密钥:")翻译[k] = new_key时间.sleep(4)对于旧的,新的 translate.items():name_dict[new] = name_dict.pop(old)

I would like some help with understanding why this code is not working as expected.

If one wants to change the key of a dictionary but keep the value, he/she might use:

d[new_key] = d.pop[old_key]

I want to modify all the keys (and keep the values in place) but the code below skips certain lines - ("col2") remains untouched. Is it because dictionaries are unordered and I keep changing the values in it?

How would I go about changing the keys and keep the values without creating a new dictionary?

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'
" % (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)

解决方案

It's never a good idea to change the object you're iterating over. Normally dict even throws an exception when you attempt it:

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: dictionary changed size during iteration

However in your case you add one item for every removed item. That makes it more convolved. To understand what's happening you need to know that a dictionary is somewhat like a sparse table. For example a dictionary like {1: 1, 3: 3, 5: 5} could look like this (this changed in Python 3.6, for 3.6 and newer the following isn't correct anymore):

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

That's also the order in which it is iterated. So in the first iteration it will go to the second item (where the 1: 1 is stored). Let's assume you change the key to 2 and remove the key 1 the dict would look like this:

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

But we're still at the second line, so the next iteration it will go to the next "not-empty" entry which is 2: 1. Oups ...

It's even more complicated with strings as keys because string hashes are randomized (on a per session basis) so the order inside the dictionary is unpredictable.

In 3.6 the internal layout was changed a bit but something similar happens here.

Assuming you have this loop:

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)

The initial layout is like this:

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

The first loop removes 1 but adds 7. Because dictionaries are ordered in 3.6 this inserts a placeholder where 1 had been:

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

This goes on until you replace 4 with 10.

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

But when you replace 5 with 11 the dictionary will need to increase it's size. Then something special happens: The placeholders are removed:

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

So, we were at position 5 in the last iteration and now we change line 6. But line 6 contains 11: 5 right now. Oups...

Never change the object you're iterating over: Don't mess with the keys during iteration (values are okay)!

You could instead keep a "translation table" (don't know if that violates your "without creating a new dict" requirement but you need some kind of storage to make your code work correctly) and do the renaming after the loop:

translate = {}
for k, v in name_dict.items():
    print("This is the key: '%s' and this is the value '%s'
" % (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)

这篇关于如何使用 d.items() 更改 for 循环中的所有字典键?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆