将字典映射到另一个字符的单行表达式

时间:2011-01-15 09:49:39

标签: python

我有像

这样的词典
d = {'user_id':1, 'user':'user1', 'group_id':3, 'group_name':'ordinary users'}

和“映射”字典如:

m = {'user_id':'uid', 'group_id':'gid', 'group_name':'group'}

我想用第二个键中的“替换”第一个字典中的键(例如将'user_id'替换为'uid'等) 我知道密钥是不可变的,我知道如何用'if / else'语句来做。

但也许有办法在一行表达式中做到这一点?

4 个答案:

答案 0 :(得分:16)

不确定

d = dict((m.get(k, k), v) for (k, v) in d.items())

答案 1 :(得分:15)

让我们从@karlknechtel那里获取优秀的代码,看看它的作用:

>>> d = dict((m.get(k, k), v) for (k, v) in d.items())
{'gid': 3, 'group': 'ordinary users', 'uid': 1, 'user': 'user1'}

但它是如何运作的?

要构建字典,您可以使用dict()功能。它需要一个元组列表。在3.x和> 2.7中,您还可以使用字典理解(请参阅@nightcracker的回答)。

让我们剖析一下dict的论点。首先,我们需要m中所有项目的列表。每个项目都是格式(键,值)的元组。

>>> d.items()
[('group_id', 3), ('user_id', 1), ('user', 'user1'), ('group_name', 'ordinary users')]

给定键值k,我们可以通过mm[k]获得正确的键值。

>>> k = 'user_id'
>>> m[k]
'uid'

不幸的是,并非d中的所有密钥都存在于m

>>> k = 'user'
>>> m[k]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'user'

要解决此问题,您可以使用d.get(x, y),如果密钥d[x]存在则返回x,如果不存在,则返回默认值y。现在,如果k中不存在来自d的密钥m,我们只保留它,因此默认值为k

>>> m.get(k, k).
'user'

现在我们准备构建一个元组列表以供给dict()。要在一行中构建列表,我们可以使用list comprehension

要构建一个正方形列表,您可以这样写:

>>> [x**2 for x in range(5)]
[0, 1, 4, 9, 16]

在我们的案例中,它看起来像这样:

>>> [(m.get(k, k), v) for (k, v) in d.items()]
[('gid', 3), ('uid', 1), ('user', 'user1'), ('group', 'ordinary users')]

那是满口的,让我们再看一遍。

给我一​​个列表[...],其中包含元组:

[(.., ..) ...]

我想为x中的每个项d添加一个元组:

[(.., ..) for x in d.items()]

我们知道每个项目都是包含两个组件的元组,因此我们可以将其扩展为两个变量kv

[(.., ..) for (k, v) in d.items()]

每个元组都应该使用m作为第一个分量的正确密钥,如果m中不存在k则为k,以及来自d的值。

[(m.get(k, k), v) for (k, v) in d.items()]

我们可以将其作为参数传递给dict()

>>> dict([(m.get(k, k), v) for (k, v) in d.items()])
{'gid': 3, 'group': 'ordinary users', 'uid': 1, 'user': 'user1'}

看起来不错!但是等等,你可能会说,@ karlknechtel没有使用方括号。

是的,他没有使用列表理解,而是使用generator expression。简单来说,不同之处在于列表推导在内存中构建整个列表,而生成器表达式一次计算项目。如果列表作为中间结果,使用生成器表达式通常是个好主意。在这个例子中,它并没有真正有所作为,但习惯这是一个好习惯。

等效的生成器表达式如下所示:

>>> ((m.get(k, k), v) for (k, v) in d.items())
<generator object <genexpr> at 0x1004b61e0>

如果将生成器表达式作为参数传递给函数,则通常可以省略外部括号。最后,我们得到:

>>> dict((m.get(k, k), v) for (k, v) in d.items())
{'gid': 3, 'group': 'ordinary users', 'uid': 1, 'user': 'user1'}

在一行代码中发生了很多事情。有人说这是不可读的,但是一旦习惯了它,将这些代码延伸到几行似乎是不可读的。只是不要过头了。列表理解和生成器表达式非常强大,但强大的功能带来了巨大的责任。给一个好问题+1!

答案 2 :(得分:6)

在3.x中:

d = {m.get(key, key):value for key, value in d.items()}

它的工作原理是创建一个新字典,其中包含d中的每个值并映射到新密钥。密钥的检索方式如下:m[key] if m in key else key,但随后使用默认的.get函数(如果密钥不存在,则支持默认值)。

答案 3 :(得分:1)

为什么要在一行中完成?

result = {}
for k, v in d.iteritems():
    result[m.get(k, k)] = v