将元组列表映射为字典
我有一个从数据库表中提取出来的元组列表,格式是(键,外键,值)。这里的键和外键之间是多对一的关系,我想把它转换成一个字典,字典的索引是外键,内容是所有与该外键相关的值的总和,也就是 { 外键 : 值的总和 }。我写的代码有点啰嗦:
myDict = {}
for item in myTupleList:
if item[1] in myDict:
myDict [ item[1] ] += item[2]
else:
myDict [ item[1] ] = item[2]
但是在看到这个问题的回答,或者这两个 链接后,我觉得应该有更简洁的方法来实现我想做的事情。如果这个问题已经有人问过,我没看到,能给我个链接我就把这个问题删掉。
5 个回答
这是我(开玩笑的)回答:
myDict = reduce(lambda d, t: (d.__setitem__(t[1], d.get(t[1], 0) + t[2]), d)[1], myTupleList, {})
虽然看起来很丑,也不太好,但我来解释一下它是怎么工作的。
首先,传给 reduce 的第一个参数是 lambda d, t: (d.__setitem__(t[1], d.get(t[1], 0) + t[2]), d)[1]
。我稍后会详细讲这个,但现在我就叫它 joe
(没有冒犯任何叫 Joe 的人)。reduce 函数基本上是这样工作的:
joe(joe(joe({}, myTupleList[0]), myTupleList[1]), myTupleList[2])
这是针对一个包含三个元素的列表。正如你所看到的,它主要是用第一个参数来逐步累积每个结果,最终得到答案。在这个例子中,最终的答案就是你想要的字典。
接下来讲讲 joe
本身。这里是 joe
的一个 def
版本:
def joe(myDict, tupleItem):
myDict[tupleItem[1]] = myDict.get(tupleItem[1], 0) + tupleItem[2]
return myDict
不幸的是,在 Python 的 lambda
中不允许使用 =
或 return
,所以我们得想办法绕过这个限制。我通过直接调用字典的 __setitem__
函数来解决没有 =
的问题。为了处理没有返回值的问题,我创建了一个包含 __setitem__
返回值和字典的元组,然后返回这个元组中包含字典的元素。我会慢慢修改 joe
,让你看到我是怎么做到的。
首先,去掉 =
:
def joe(myDict, tupleItem):
# Using __setitem__ to avoid using '='
myDict.__setitem__(tupleItem[1], myDict.get(tupleItem[1], 0) + tupleItem[2])
return myDict
接下来,让整个表达式的结果是我们想要返回的值:
def joe(myDict, tupleItem):
return (myDict.__setitem__(tupleItem[1], myDict.get(tupleItem[1], 0) + tupleItem[2]),
myDict)[1]
在我的 Python 编程中,我遇到过很多次使用 reduce
和 dict
的场景。在我看来,dict
可以增加一个成员函数 reduceto(keyfunc, reduce_func, iterable, default_val=None)
。keyfunc
会从可迭代对象中获取当前值并返回键。reduce_func
会获取字典中已有的值和可迭代对象中的值,并返回字典的新值。default_val
是如果字典缺少某个键时传入 reduce_func
的值。返回值应该是字典本身,这样你就可以做一些像这样的操作:
myDict = dict().reduceto(lambda t: t[1], lambda o, t: o + t, myTupleList, 0)
在编程中,有时候我们需要让程序在特定的条件下执行某些操作。这就像给程序设定了一些规则,只有当这些规则被满足时,程序才会继续运行。
比如说,你可能希望程序在用户输入正确的密码后才能进入某个页面。这个时候,你就需要用到条件判断。条件判断就像是在问一个问题,如果答案是“是”,那么就执行某个操作;如果答案是“否”,那么就执行另一个操作。
在代码中,这种条件判断通常用“if”语句来实现。你可以把“if”想象成一个门,只有当条件满足时,门才会打开,程序才能继续往下走。
总之,条件判断是让程序根据不同情况做出不同反应的一个重要工具。掌握了这个概念,你就能写出更灵活、更智能的程序了。
from collections import defaultdict
myDict = defaultdict(int)
for _, key, value in myTupleList:
myDict[key] += value
假设你所有的值都是 int
类型,你可以使用 defaultdict
来让事情变得简单一些:
from collections import defaultdict
myDict = defaultdict(int)
for item in myTupleList:
myDict[item[1]] += item[2]
defaultdict
就像一个字典,但如果你试图获取一个不存在的键,它会用一个可调用的对象返回的值来填充这个键。在这个例子中,就是 int
,当没有参数调用时,它会返回 0。
更新:感谢 @gnibbler 提醒我,元组可以在 for 循环中解包:
from collections import defaultdict
myDict = defaultdict(int)
for _, key, val in myTupleList:
myDict[key] += val
在这里,包含三个元素的元组被解包到变量 _
、key
和 val
中。_
是 Python 中一个常用的占位符名称,表示这个值其实并不重要。使用这个方法,我们可以避免复杂的 item[1]
和 item[2]
索引。如果 myTupleList
中的元组大小不一致,我们就不能依赖这个方法,但我敢打赌它们都是一样的。
(我们还避免了让别人看代码时觉得它有问题,因为写代码的人以为数组是从 1 开始计数的,这也是我第一次看到这段代码时的想法。直到我读了问题,我才明白这一点。不过在上面的循环中,很明显 myTupleList
是一个包含三个元素的元组,我们根本不需要第一个元素。)