Python中是否有“ multimap”实现?


75

我是新来的Python,和我熟悉的实现屈德宁其他 语言。Python是否内置了这样的数据结构,或者在常用的库中可用?

为了说明我所说的“ multimap”:

a = multidict()
a[1] = 'a'
a[1] = 'b'
a[2] = 'c'

print(a[1])  # prints: ['a', 'b']
print(a[2])  # prints: ['c']

3
@ccfenix,我添加了一个我认为您想要的示例。如果这是错误的,请进行编辑以使示例正确。一个例子可以帮助人们回答你的问题。他们需要知道您在寻找什么。
steveha

是的,正是我想要的,谢谢你,史蒂夫哈!
James Bond

code.activestate.com/recipes/…似乎实现了您要使用的语法
Chozabu 2014年

1
使用a附加到a [1]的a[1] = 'b'意思会使人们阅读或维护此代码感到困惑。我建议您不要在Python中执行此操作。
poolie

Answers:


125

这样的事情在标准库中不存在。您可以使用defaultdict虽然:

>>> from collections import defaultdict
>>> md = defaultdict(list)
>>> md[1].append('a')
>>> md[1].append('b')
>>> md[2].append('c')
>>> md[1]
['a', 'b']
>>> md[2]
['c']

(而不是list您可能要使用set,在这种情况下,您将致电.add而不是.append。)


顺便说一句:看一下这两行:

a[1] = 'a'
a[1] = 'b'

这似乎表明您希望表达式a[1]等于两个不同的值。对于字典而言,这是不可能的,因为它们的键是唯一的,并且每个键都与一个值相关联。但是,您可以做的是一张一张地提取与给定键关联的列表中的所有值。您可以使用,iter之后再依次调用next。或者,您可以只使用两个循环:

>>> for k, v in md.items():
...     for w in v:
...         print("md[%d] = '%s'" % (k, w))
... 
md[1] = 'a'
md[1] = 'b'
md[2] = 'c'

9

只为将来的访客。目前,Multimap有python实现。可以通过pypi获得


2
“与其他项目相比,该项目的定义质量是,同一键映射的值未一起排序。” 这与使用defaultdict(set)有何不同?
Shuklaswag

它不会在您的链接上说“已排序”,而是说“已分组”。因此这不是一个集合,因为同一元素可以插入两次。我猜它的行为更像是一个排序列表。
Eyal

4

Stephan202有正确的答案,使用defaultdict。但是,如果您想要C ++ STL多图的接口和更差的性能,可以执行以下操作:

multimap = []
multimap.append( (3,'a') )
multimap.append( (2,'x') )
multimap.append( (3,'b') )
multimap.sort()

现在,当您遍历时multimap,您将获得与配对中一样的配对std::multimap。不幸的是,这意味着您的循环代码将看起来像C ++一样难看。

def multimap_iter(multimap,minkey,maxkey=None):
  maxkey = minkey if (maxkey is None) else maxkey
  for k,v in multimap:
    if k<minkey: continue
    if k>maxkey: break
    yield k,v

# this will print 'a','b'
for k,v in multimap_iter(multimap,3,3):
  print v

总而言之,defaultdict它确实很酷并且可以利用python的功能,因此您应该使用它。


4

您可以获取元组列表,然后可以像对待多图一样对其进行排序。

listAsMultimap=[]

让我们附加一些元素(元组):

listAsMultimap.append((1,'a'))
listAsMultimap.append((2,'c'))
listAsMultimap.append((3,'d'))
listAsMultimap.append((2,'b'))
listAsMultimap.append((5,'e'))
listAsMultimap.append((4,'d'))

现在排序。

listAsMultimap=sorted(listAsMultimap)

打印后,您将获得:

[(1, 'a'), (2, 'b'), (2, 'c'), (3, 'd'), (4, 'd'), (5, 'e')]

这意味着它正在作为多图工作!

请注意,如果键相同,则此处的值与multimap一样也按升序排序(对于key = 2,尽管我们未按此顺序附加键,但键b在'c'之前)。

如果要按降序获取它们,只需更改sorted()函数,如下所示:

listAsMultimap=sorted(listAsMultimap,reverse=True)

然后,您将获得如下输出:

[(5, 'e'), (4, 'd'), (3, 'd'), (2, 'c'), (2, 'b'), (1, 'a')]

同样,如果键相同,则值按降序排列。


这与具有O(1)成本的多图不同。以上是O(NlogN)。
user48956 '19

@ user48956,我想你在unordered_multimap和multimap之间感到困惑。Multimap具有O(NlogN)和NOT O(1)的复杂度。上面的实现是针对Multimap的,而不是针对unordered_multimap的,unordered_multimap使用散列来降低时间复杂度,并且平均而言具有恒定的平均时间复杂度。在此处找到差异:(en.cppreference.com/w/cpp/container/multimap)和此处:(cplusplus.com/reference/unordered_map/unordered_multimap
hafiz031

3

用Python编写此代码的标准方法是使用一个dict,其元素分别为a listset。正如stephan202所说,您可以使用defaultdict在某种程度上自动执行此操作,但不必这样做。

换句话说,我会将您的代码翻译成

a = dict()
a[1] = ['a', 'b']
a[2] = ['c']

print(a[1])  # prints: ['a', 'b']
print(a[2])  # prints: ['c']

为什么要下票?因为看起来还不够像字典?我认为,将其a[1] = 'b'视为“附加”而不是“替换”,a[1]比提供帮助更令人困惑。
poolie 2011年

2
我没有投票,但是我认为您的建议对讨论没有任何帮助,这可能解释了负面反应。您当然可以使用键的字典来表示值列表,但是这种手动实现很烦人,重复且有些容易出错。像Guava的Java Multimap这样的multimap仅仅是列表列表,但是它非常方便,因为它隐藏了该实现。您的建议是准确的,但没有任何方便。
dimo414

4
我试图提出的要点是,其他人没有做到:使用多图不是Pythonic。惯用的方式是集合的决定。
poolie

我喜欢pythonic的讨论。我来自Java和Perl,我怀疑@ dimo414的担心与添加新密钥时实例化列表有关。在这方面,答案可能是关于pythonic的扩展。
克里斯(Chris)

...走了一步,更详细地研究了defaultdict,并将其作为解决方案。我猜这是因为您没有解决创建defaultdict为您所做的列表的问题。
克里斯(Chris)

3

或子类dict

class Multimap(dict):
    def __setitem__(self, key, value):
        if key not in self:
            dict.__setitem__(self, key, [value])  # call super method to avoid recursion
        else
            self[key].append(value)

2
但是,这不会表现得完全像字典。stackoverflow.com/questions/3387691/...
johncip


-4

我不清楚您的示例的语义

a[1] = 'a'
a[1] = 'b' #??

是第二行a[1] = 'b'应该替换[1]处的元素吗?如果是,那么您需要使用字典。如果不是,则需要使用列表字典(如已建议)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.