将元组列表映射为字典

5 投票
5 回答
10593 浏览
提问于 2025-04-15 18:56

我有一个从数据库表中提取出来的元组列表,格式是(外键)。这里的键和外键之间是多对一的关系,我想把它转换成一个字典,字典的索引是外键,内容是所有与该外键相关的值的总和,也就是 { 外键 : 值的总和 }。我写的代码有点啰嗦:

myDict = {}
for item in myTupleList:
    if item[1] in myDict:
        myDict [ item[1] ] += item[2]
    else:
        myDict [ item[1] ] = item[2]

但是在看到这个问题的回答,或者这两个 链接后,我觉得应该有更简洁的方法来实现我想做的事情。如果这个问题已经有人问过,我没看到,能给我个链接我就把这个问题删掉。

5 个回答

4

这是我(开玩笑的)回答:

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 编程中,我遇到过很多次使用 reducedict 的场景。在我看来,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)
5

在编程中,有时候我们需要让程序在特定的条件下执行某些操作。这就像给程序设定了一些规则,只有当这些规则被满足时,程序才会继续运行。

比如说,你可能希望程序在用户输入正确的密码后才能进入某个页面。这个时候,你就需要用到条件判断。条件判断就像是在问一个问题,如果答案是“是”,那么就执行某个操作;如果答案是“否”,那么就执行另一个操作。

在代码中,这种条件判断通常用“if”语句来实现。你可以把“if”想象成一个门,只有当条件满足时,门才会打开,程序才能继续往下走。

总之,条件判断是让程序根据不同情况做出不同反应的一个重要工具。掌握了这个概念,你就能写出更灵活、更智能的程序了。

from collections import defaultdict

myDict = defaultdict(int)

for _, key, value in myTupleList:
    myDict[key] += value
10

假设你所有的值都是 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

在这里,包含三个元素的元组被解包到变量 _keyval 中。_ 是 Python 中一个常用的占位符名称,表示这个值其实并不重要。使用这个方法,我们可以避免复杂的 item[1]item[2] 索引。如果 myTupleList 中的元组大小不一致,我们就不能依赖这个方法,但我敢打赌它们都是一样的。

(我们还避免了让别人看代码时觉得它有问题,因为写代码的人以为数组是从 1 开始计数的,这也是我第一次看到这段代码时的想法。直到我读了问题,我才明白这一点。不过在上面的循环中,很明显 myTupleList 是一个包含三个元素的元组,我们根本不需要第一个元素。)

撰写回答