dictionary dictionary - Existe-t-il une implémentation "multimap" en Python?



append add (7)

Je suis nouveau à Python, et je suis familier avec les implémentations de Multimaps dans d' other languages . Python a-t-il une telle structure de données intégrée ou est-elle disponible dans une bibliothèque couramment utilisée?

Pour illustrer ce que je veux dire par "multimap":

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

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

Answers

Juste pour les futurs visiteurs. Actuellement, il existe une implémentation python de Multimap. C'est disponible via pypi


Une telle chose n'est pas présente dans la bibliothèque standard. Vous pouvez utiliser un defaultdict si:

>>> 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']

(Au lieu de list vous pouvez utiliser set , auquel cas vous appellerez .add au lieu de .append .)

En aparté : regardez ces deux lignes que vous avez écrites:

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

Cela semble indiquer que vous voulez que l'expression a[1] soit égale à deux valeurs distinctes. Cela n'est pas possible avec les dictionnaires car leurs clés sont uniques et chacune d'elles est associée à une seule valeur. Ce que vous pouvez faire, cependant, est d'extraire toutes les valeurs dans la liste associée à une clé donnée, une par une. Vous pouvez utiliser iter suivi d'appels successifs à next pour cela. Ou vous pouvez simplement utiliser deux boucles:

>>> 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'

La façon standard d'écrire ceci en Python est avec une dict dont les éléments sont chacun une list ou un set . Comme le dit stephan202 , vous pouvez l'automatiser avec un defaultdict, mais vous n'êtes pas obligé de le faire.

En d'autres termes, je traduirais votre code à

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

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

Stephan202 a la bonne réponse, utilisez defaultdict . Mais si vous voulez quelque chose avec l'interface de CML STL multimap et des performances bien pires, vous pouvez le faire:

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

Maintenant, quand vous parcourez multimap , vous obtiendrez des paires comme vous le feriez dans un std::multimap . Malheureusement, cela signifie que votre code de boucle commencera à être aussi laid que 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

En résumé, defaultdict est vraiment cool et tire parti de la puissance de python et vous devriez l'utiliser.


Je ne comprends pas clairement la sémantique de votre exemple

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

Est la deuxième ligne a[1] = 'b' censé remplacer l'élément à [1]. Si oui, alors vous devez utiliser un dictionnaire. Sinon - vous devez utiliser le dictionnaire des listes (comme déjà suggéré)


Ou sous-classe 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)

D'autres ont expliqué le fonctionnement des métaclasses et leur intégration dans le système de types Python. Voici un exemple de ce qu'ils peuvent être utilisés. Dans un framework de test que j'ai écrit, je voulais garder une trace de l'ordre dans lequel les classes étaient définies, afin de pouvoir les instancier ultérieurement dans cet ordre. J'ai trouvé le plus facile de faire cela en utilisant une métaclasse.

class MyMeta(type):

    counter = 0

    def __init__(cls, name, bases, dic):
        type.__init__(cls, name, bases, dic)
        cls._order = MyMeta.counter
        MyMeta.counter += 1

class MyType(object):              # Python 2
    __metaclass__ = MyMeta

class MyType(metaclass=MyMeta):    # Python 3
    pass

Tout ce qui est une sous-classe de MyType obtient alors un attribut de classe _order qui enregistre l'ordre dans lequel les classes ont été définies.





python dictionary