在Python中,map<int, vector<int>>的等价物是什么?

9

在C++中经常会做这样的事情:

typedef map<int, vector<int> > MyIndexType;

然后我可以像这样使用它:

MyIndexType myIndex;
for( ... some loop ...)
{
  myIndex[someId].push_back(someVal);
}

如果地图中没有条目,代码将插入一个新的空向量,然后将其附加到其中。
在Python中,它看起来像这样:
myIndex = {}

for (someId,someVal) in collection:
   try:
      myIndex[someId].append(someVal)
   except KeyError:
      myIndex[someId] = [someVal]

尝试使用except语句有点丑陋。在字典声明时,是否有一种方法可以告诉字典遇到KeyError时要插入的对象类型?

你应该在你的C++代码中使用multimap<>。 - SoapBox
一个multimap不一定是这里正确的数据结构。在map内嵌套一个vector是可以的。 - Konrad Rudolph
同意:multimap<int,int> 不会像 map<int,vector<int>> 一样保留插入的顺序。 - Alastair
这个问题更多是关于如何将默认条目添加到您的集合中。我还使用了很多类似问题的map<SomeKey,SomeStruct>集合。 - Jeroen Dirks
不要在这里使用try except,而是使用“in”运算符(它会为字典调用has_key()方法)。 - André
@André:这取决于缺失键的出现频率。如果有很多缺失键,key in dict可能更可取。无论如何,dict.setdefault()或collections.defaultdict都可以解决这个问题。 - jfs
5个回答

15

您想使用:

from collections import defaultdict
myIndex = defaultdict(list)
myIndex[someId].append(someVal)

Python标准库中的defaultdict对象

以下是Python文档中的示例用法:

>>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
>>> d = defaultdict(list)
>>> for k, v in s:
        d[k].append(v)

>>> d.items()
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]

10

也许是这样的:

myIndex = {}
for (someId,someVal) in collection:
    myIndex.setdefault(someId, []).append(someVal)

这基本上是比ddaa的回答更好的做事方式。 - Jerub
@Jerub:我不同意。使用defaultdict更容易阅读,并且具有优点,即在不添加新键时不会创建并立即销毁新的空列表(尽管在实践中对于列表来说略慢 - 对于某些类型来说可能很重要)。 - Brian
我同意,使用 setdefault() 是一个不错的选择。 - Jeremy Cantrell
当您构建一个字典并计划将其传递给其他人时(或者您只是有对同一字典的单独查找,不应返回默认值),使用setdefault更好。当您在一个地方使用字典和/或所有查找都应返回默认值时,使用defaultdict更好。(很少情况下,setdefaultget的组合可以作为代码的(临时?)内存优化,以修复错误使用defaultdict的情况) - Rosh Oxymoron

2

为了完善Alastair的回答: 还有一个与setdefault相对应的get方法,它被称为get(而不是getdefault,这可能会让人误解):

myIndex = {}
someId = None
myList = myIndex.get(someId, []) # myList is [] now

1

从Python 2.5开始,您可以通过实现来获取setdefault的行为或使用defaultdict

__missing__(k)

就像注释10中这里所示。


0
这个怎么样?它可能不是性能最优的,但我认为它是“可能可行的最简单的事情”。
myIndex = {}

for (someId,someVal) in collection:
   if someId not in myIndex:
       myIndex[someId] = []
   myIndex[someId].append(someVal)

你实际上在这里进行了2次查找。比所需的多一次。 - Jeroen Dirks
这被称为“先看清再跳”(LBYL)。更Pythonic的是EAFP(谷歌一下 :-))。在这种情况下: 尝试: myIndex[someID].append(someVal) 除了KeyError之外: myIndex[someID] = [someVal]当然,现在我们有defaultdict,它甚至更好 :-) - John Fouhy
示例的最后一行应为 myIndex[someId].append(someVal),请注意 'append' 中的小写字母 'a'。 - Boris Gorelik
我不明白为什么这个被踩了:对于这个问题来说,它比setdefault或者defaultdict更糟糕,但是它比try-except的变体更简洁和清晰(虽然多了一次查找),而且它是一个有效的解决方案。特别是,在创建默认值是一个昂贵的操作,并且它与__missing__一样强大(即比defaultdict更强大)时,它是setdefault的一个有效替代品。 - Rosh Oxymoron

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