2009-11-13 7 views
44

Soy nuevo en Python, y estoy familiarizado con las implementaciones de Multimaps en otherlanguages. ¿Tiene Python una estructura de datos integrada o está disponible en una biblioteca de uso común?¿Hay una implementación 'multimap' en Python?

Para ilustrar lo que quiero decir por "multimap":

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

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

@ccfenix, agregué un ejemplo de lo que creo que usted quería. Si esto es incorrecto, edite para que el ejemplo sea correcto. Un ejemplo ayuda a las personas a responder su pregunta; ellos necesitan saber lo que estás buscando. – steveha

+0

yah, exactamente lo que quiero, gracias steveha! –

+0

http://code.activestate.com/recipes/576835-multimap-associating-multiple-values-to-a-key/ parece implementar la sintaxis que está después de – Chozabu

Respuesta

85

Tal cosa no está presente en la biblioteca estándar. Puede utilizar un defaultdict sin embargo:

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

(En lugar de list es posible que desee utilizar set, en cuyo caso se podría llamar .add en lugar de .append.)


Como acotación al margen : observe estas dos líneas que escribió:

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

Esto parece o indique que desea que la expresión a[1] sea igual a dos valores distintos. Esto no es posible con los diccionarios porque sus claves son únicas y cada una de ellas está asociada a un solo valor. Lo que puede hacer, sin embargo, es extraer todos los valores dentro de la lista asociada con una clave determinada, uno por uno. Puede usar iter seguido de llamadas sucesivas al next para eso. O simplemente puede utilizar dos bucles:

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

que no entienden claramente la semántica de tu ejemplo

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

Es segunda línea a[1] = 'b' supone que sustituir el elemento en [1]. En caso afirmativo, debes usar el diccionario. De lo contrario, debe usar el diccionario de listas (como ya se sugirió)

+4

Lea lo que es un mapa múltiple: http://www.cplusplus.com/reference/stl/multimap/ – Casebash

1

Actualmente, no hay múltiples mapas en las bibliotecas estándar de Python.

WebOb tiene una clase MultiDict utilizada para representar valores de formulario HTML, y es utilizada por algunos frameworks de Python Web, por lo que la implementación se prueba en batalla.

Werkzeug también tiene una clase MultiDict, y por la misma razón.

1

La forma estándar de escribir esto en Python es con un dict cuyos elementos son cada uno un list o set. Como stephan202 says, puede automatizar algo esto con un default, pero no es necesario.

En otras palabras que se traduciría a su código

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

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

¿Por qué los votos a favor? Porque no se ve lo suficiente como un dict? Creo que tratar 'a [1] = 'b'' como añadido a, en lugar de reemplazar,' a [1] ', es más confuso que útil. – poolie

+2

No he votado negativamente, pero creo que su sugerencia no agrega nada a la discusión, lo que podría explicar la respuesta negativa. Ciertamente puede usar un dictado de claves para listas de valores, pero esta implementación manual es molesta, repetitiva y propensa a errores. Un multimapa, como [Guava's Multimap] (http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/ArrayListMultimap.html) para Java, no es más que un mapa de listas , pero es tremendamente conveniente exactamente porque oculta esa implementación. Su sugerencia es precisa, pero carece de conveniencia. – dimo414

+3

El punto que estaba tratando de hacer, que no está hecho por los otros, es: usar un multimapa no es Pythonic. La forma idiomática es una dicción de conjuntos. – poolie

2

Stephan202 tiene la respuesta correcta, utilice defaultdict.Pero si quieres algo con la interfaz de C++ multimap STL y mucho peor rendimiento, puede hacer esto:

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

Ahora cuando iterar a través multimap, obtendrá pares como lo haría en un std::multimap. Desafortunadamente, eso significa que su código de bucle comenzará a verse tan feo como 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 resumen, defaultdict es realmente fresco y aprovecha la potencia de Python y que se debe utilizar.

2

o subclase 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) 
+1

Esto no se va a comportar exactamente como un dict, sin embargo. http://stackoverflow.com/questions/3387691/python-how-to-perfectly-override-a-dict – johncip

9

Sólo para futuros visitantes. Actualmente hay una implementación de Python de Multimap. Está disponible a través de pypi

+0

"La calidad de definición de este proyecto frente a otros es que los valores asignados por la misma clave no se ordenan juntos". ¿En qué se diferencia esto de usar 'defaultdict (set)'? – Shuklaswag

Cuestiones relacionadas