在字典列表中更新列表值

3

我有一个字典列表(类似于JSON格式)。我想对列表中每个字典的一个键应用一个函数。

>> d = [{'a': 2, 'b': 2}, {'a': 1, 'b': 2}, {'a': 1, 'b': 2}, {'a': 1, 'b': 2}]

# Desired value
[{'a': 200, 'b': 2}, {'a': 100, 'b': 2}, {'a': 100, 'b': 2}, {'a': 100, 'b': 2}]

# If I do this, I can only get the changed key
>> map(lambda x: {k: v * 100 for k, v in x.iteritems() if k == 'a'}, d)
[{'a': 200}, {'a': 100}, {'a': 100}, {'a': 100}]

# I try to add the non-modified key-values but get an error
>> map(lambda x: {k: v * 100 for k, v in x.iteritems() if k == 'a' else k:v}, d)

SyntaxError: invalid syntax
File "<stdin>", line 1
map(lambda x: {k: v * 100 for k, v in x.iteritems() if k == 'a' else k:v}, d)

我该如何实现这个功能?
编辑:'a'和'b'并不是唯一的键。这些只是为了演示目的而选择的。

我们是否应该假设a将始终存在于这些字典中?如果不是,那么期望的是什么? - Miket25
是的,这些字典的键将会是相同的。 - drum
5个回答

7
遍历该列表并更新所需的字典项。
lst = [{'a': 2, 'b': 2}, {'a': 1, 'b': 2}, {'a': 1, 'b': 2}, {'a': 1, 'b': 2}]

for d in lst:
    d['a'] *= 100

使用列表推导式可以提高速度,但会创建一个新的列表和n个新的字典。如果你不想改变原来的列表,这很有用。以下是示例代码:
new_lst = [{**d, 'a': d['a']*100} for d in lst]

在Python 2.X中,我们不能使用{**d},因此我基于update方法构建了custom_update。代码如下:
def custom_update(d):
    new_dict = dict(d)
    new_dict.update({'a':d['a']*100})
    return new_dict

[custom_update(d) for d in lst]

如果您希望为列表中的每个元素更新不同的键,则可以这样做。
keys = ['a', 'b', 'a', 'b'] # keys[0] correspond to lst[0] and keys[0] correspond to lst[0], ...

for index, d in enumerate(lst):
    key = keys[index]
    d[key] *= 100

使用列表推导式
[{**d, keys[index]: d[keys[index]] * 100} for index, d in enumerate(lst)]

在Python 2.x中,列表推导式将会是:
def custom_update(d, key):
    new_dict = dict(d)
    new_dict.update({key: d[key]*100})
    return new_dict

[custom_update(d, keys[index]) for index, d in enumerate(lst)]

@drum {**d} 在 Python2 中无法工作,我已更新答案并添加了兼容 Python 2.x 的代码。 - taoufik A

5

你可以在列表推导式中更好地使用内联条件语句(三元表达式):

>>> d = [{'a': 2, 'b': 2}, {'a': 1, 'b': 2}, {'a': 1, 'b': 2}, {'a': 1, 'b': 2}]
>>> d2 = [{k: v * 100 if k == 'a' else v for k, v in i.items()} for i in d]
>>> d2
[{'a': 200, 'b': 2}, {'a': 100, 'b': 2}, {'a': 100, 'b': 2}, {'a': 100, 'b': 2}]

1
你的map()调用快要生效了,你只需要改变字典推导式的顺序,并将else k:v改为else v
>>> d = [{'a': 2, 'b': 2}, {'a': 1, 'b': 2}, {'a': 1, 'b': 2}, {'a': 1, 'b': 2}]
>>> list(map(lambda x: {k: v * 100 if k == 'a' else v for k, v in x.items()}, d))
[{'a': 200, 'b': 2}, {'a': 100, 'b': 2}, {'a': 100, 'b': 2}, {'a': 100, 'b': 2}]

0
在您编辑了“'a'和'b'不是唯一的键。这些仅用于演示目的”之后,这里有一个非常简单的map函数,仅更改'a'的值,其余保持不变
map(lambda x: x.update({'a': x['a']*100}), d)

我的原始答案是:

我认为最简单和最合适的方法是在 d 中进行迭代,并利用每个 d 中的项都是一个具有键 'a''b' 的字典这一事实:

res = [{'a':e['a']*100, 'b':e['b']} for e in d]

结果:

[{'a': 200, 'b': 2}, {'a': 100, 'b': 2}, {'a': 100, 'b': 2}, {'a': 100, 'b': 2}]

通过您的更新,地图将返回一个列表/迭代器,同时更新现有列表。虽然很整洁,但我不会说它非常干净。 - drum

0

如果您正在使用函数,您可能希望提供目标键和相应的值:

d = [{'a': 2, 'b': 2}, {'a': 1, 'b': 2}, {'a': 1, 'b': 2}, {'a': 1, 'b': 2}]
f = lambda new_val, d1, key='a': {a:b*new_val if a == key else b for a, b in d1.items()}
new_d = list(map(lambda x:f(100, x), d))

输出:

[{'a': 200, 'b': 2}, {'a': 100, 'b': 2}, {'a': 100, 'b': 2}, {'a': 100, 'b': 2}]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接