以最佳方式从字典中删除所有值

时间:2018-12-14 10:21:09

标签: python python-3.x dictionary

我有类似的字典:

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 :(得分:3)

如果您需要就地更新字典 ,则必须对键进行迭代,因此您的键是一种很好的可读方法。它比更新词典甚至使用相同键创建新词典的替代方法还快!

您可以挂断items()调用,您对值不感兴趣。只需直接在字典上循环以获取键:

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

另一种方法是使用dict.fromkeys()创建一个新的空字典。要就地更新现有词典 (以便对同一词典的其他引用可以看到更改),您可以调用z.update()并传入新词典:

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

缺点是您可能需要添加注释以解释该行应达到的目的。它也是 slower ,因为创建新对象只是为了更新现有对象。另外,您想使用dict.fromkeys()作为第二个参数,以小心。它是一个单个值,可用于所有键。如果您要使用可变值(如列表),则这很重要。如果您只需要一本 new 词典,那么您就不用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循环都是无可争议的赢家。

答案 1 :(得分:1)

结帐方法fromkeys 就是z = z.fromkeys(z, '') 希望有帮助

答案 2 :(得分:1)

您不需要.items(),因此可以简化代码:

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

我不认为有一个单行代码可以做同样的事情,并且同样高效/可读。在IMO上使用循环是完全可以的(除非有特定的原因为什么您需要单个函数调用)。

答案 3 :(得分:0)

z = dict.fromkeys(z.keys(), "")

答案 4 :(得分:0)

您可以使用fromkeys通过键列表创建字典,并指定应为“空”值。

empty_dict = dict.fromkeys(original_dict.keys(), '')

答案 5 :(得分:0)

总结和计时各种发布的答案,它们似乎在运行时中大致相等。

我首先创建一个相对较大的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())的{​​{3}},我通常更喜欢露骨

原位突变时:

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

在162毫秒±6.15毫秒处稍快一点。