【问题标题】:Map list of tuples into a dictionary将元组列表映射到字典中
【发布时间】:2011-01-13 17:06:11
【问题描述】:

我有一个从数据库中的表中提取的元组列表,看起来像(keyforeignkeyvalue)。键和外键之间存在多对一关系,我想将其转换为由外键索引的字典,其中包含具有该外键的所有值的总和,即 { foreignkeysumof() }。我写了一些比较冗长的东西:

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

但是在看到this question's 答案或these two 之后,必须有一种更简洁的方式来表达我想做的事情。如果这是重复的,我错过了,如果你能提供链接,我会删除这个问题。

【问题讨论】:

  • 也许题外话,但我会问...为什么不在数据库级别完成?这就是 DBMS 擅长的事情......
  • 它实际上不是数据库,而是通过将其视为数据库的接口进行访问。这只是一堆平面文件。

标签: python list dictionary tuples


【解决方案1】:

假设您的所有值都是ints,您可以使用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

在这里,3 项元组被解压缩为变量 _keyval_ 是 Python 中常见的占位符名称,用于表示该值并不重要。使用它,我们可以避免毛茸茸的item[1]item[2] 索引。如果myTupleList 中的元组大小不同,我们就不能依赖它,但我敢打赌。

(我们也避免了有人看到代码并认为它​​已损坏的情况,因为作者认为数组是 1-indexed,这是我第一次阅读代码时的想法。直到我没有缓解这种情况阅读问题。然而,在上面的循环中,很明显myTupleList 是三个元素的元组,我们不需要第一个。)

【讨论】:

  • myDict = reduce(lambda d, t: (d[t[1]] += t[2], d)[1], myTupleList, defaultdict(int)) - 你知道,每个人都应该使用 reduce! 咧嘴一笑
  • Omnifarious,你能把它作为答案发布并解释一下吗?这看起来很有趣。我正在寻找任何可以教会我新东西的东西,尤其是功能性的答案。
  • @wheaties,好吧,既然你问了。 不过,我更喜欢 Chris 的解决方案。在这种情况下,reduce 模糊不清。无论如何我的解决方案有点错误,但我会发布正确的版本。
【解决方案2】:
from collections import defaultdict

myDict = defaultdict(int)

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

【讨论】:

  • 元组列表中有三个值,第一个没有使用。但简单的解决方法是将_, 放在key 之前,所以+1。
  • 这行不通,因为myTupleList 是一个三元素元组。你会得到ValueError: too many values to unpack
  • @Chris Lutz,如果你修复了它,我不会介意...... :)
  • @gnibbler - 如果人们编辑他们的答案,有些人会有点生气,但是谢谢。
  • 我认为这个可能比 Chris 的原始版本效率更高。
【解决方案3】:

这是我(嘴上)的回答:

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

不幸的是,=return 在 Python lambda 中不允许使用任何形式,因此必须绕过。我通过直接调用dicts __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)

【讨论】:

  • 感谢发布。这是丑陋和难以理解的,但至少它是有教育意义的。我非常喜欢列表推导,我希望可能有某种我可以利用的字典推导。我已经接受了他的回答。它尽可能简洁。
  • @wheaties,Python 的较新版本(尽管我不确定它们必须有多新)确实具有字典理解。我不肯定你可以让他们以你想要的方式在这里为你工作。我确实更新了我的答案以添加一个不错的功能,该功能可以添加到dict 界面中,这将使此类情况更容易处理。
  • python 3 具有字典理解 docs.python.org/dev/3.0/whatsnew/3.0.html
  • @Corey Goldberg,谢谢,我认为这可能是 Py3k 的事情。而且,正如我所怀疑的那样,它们并不能帮助您有效地解决这个问题。也许简洁,但效率不高,因为没有好的方法可以通过字典键收集结果。
【解决方案4】:

也许不完全可读,但它应该可以工作:

fks = dict([ (v[1], True) for v in myTupleList ]).keys()
myDict = dict([ (fk, sum([ v[2] for v in myTupleList if v[1] == fk ])) for fk in fks ])

第一行查找所有唯一的外键。第二行通过首先构建 (fk, sum(all values for this fk)) 对的列表并将其转换为字典来构建字典。

【讨论】:

    【解决方案5】:

    查看SQLAlchemy,看看它是否能满足您的所有需求,甚至更多

    【讨论】:

      猜你喜欢
      • 2021-04-18
      • 2017-06-28
      • 1970-01-01
      • 2010-12-31
      • 1970-01-01
      • 2019-05-09
      • 2018-09-21
      • 1970-01-01
      相关资源
      最近更新 更多