2011-05-26 20 views
22

Estaba preguntando sobre la peculiaridad de construir zipmap para descubrir que aparentemente estaba haciendo mal. Así que aprendí sobre (map vector v u) en el proceso. Pero antes de este caso, había usado zipmap para hacer el trabajo de (map vector ...). ¿Funcionó entonces porque el mapa resultante era lo suficientemente pequeño como para ser resuelto?Cuándo usar `zipmap` y cuándo` map vector`?

Y a la pregunta real: qué uso tiene zipmap, y cómo/cuándo usarlo. ¿Y cuándo usar (map vector ...)?

Mi problema original requería el orden original, por lo que mapear cualquier cosa no sería una buena idea. Pero básicamente, aparte del orden de los pares resultantes, estos dos métodos son equivalentes, porque el mapa seq 'd se convierte en una secuencia de vectores.

(for [pair (map vector v (rest v))] 
    (...)) ;do with (first pair) and (last pair) 

(for [pair (zipmap v (rest v))] 
(...)) ;do with (first pair) and (last pair) 

Respuesta

37

Utilice (zipmap ...) cuando desee construya directamente un hashmap a partir de secuencias separadas de claves y valores. La salida es un HashMap:

(zipmap [:k1 :k2 :k3] [10 20 40]) 
=> {:k3 40, :k2 20, :k1 10} 

Uso (mapa vectorial ...) cuando usted está tratando de fusionar múltiples secuencias. La salida es una secuencia perezoso de vectores:

(map vector [1 2 3] [4 5 6] [7 8 9]) 
=> ([1 4 7] [2 5 8] [3 6 9]) 

Algunas notas adicionales a considerar:

  • Zipmap sólo funciona en dos secuencias de entrada (teclas + Valores), mientras mapa vectorial puede trabajar en cualquier número de secuencias de entrada. Si sus secuencias de entrada son no pares de valores clave, entonces es probable que sea un buen indicio de que debe usar el mapa vectorial en lugar del mapa postal
  • zipmap será más eficiente y simple que hacer un mapa vectorial y luego crear un hashmap a partir de la clave/pares de valores - por ejemplo (into {} (map vector [:k1 :k2 :k3] [10 20 40])) es una manera bastante complicado de hacer zipmap
  • mapa vectorial es perezoso - por lo que trae un poco de sobrecarga adicional, pero es muy útil en circunstancias en las que realmente necesita la pereza (por ejemplo, cuando se trata de secuencias infinitas)
  • Usted puede hacer (seq (zipmap ....)) para obtener una secuencia de pares clave-valor más bien como (vector de mapa ...), Sin embargo en cuenta que esto puede reordenar la secuencia de pares de clave y valor (ya que el HashMap intermedio es desordenada)
+2

Otro uso de 'zipmap' que uso todo el tiempo es crear un mapa a partir de un vector de mapas. Considere' (datos zipmap (mapa: datos de identificación)) donde los datos son un vector de mapas, cada uno de los cuales contiene un par clave/valor ': id' único. –

7

Los métodos son más o menos equivalentes. Cuando usas zipmap obtienes un mapa con pares clave/valor. Cuando iteras sobre este mapa, obtienes vectores de [valor clave]. El orden del mapa, sin embargo, no está definido. Con el constructo 'mapa' en su primer método, crea una lista de vectores con dos elementos. El orden está definido.

Zipmap puede ser un poco menos eficiente en su ejemplo. Me quedaría con el 'mapa'.

Editar: Ah, y zipmap no es flojo. Otra razón para no usarlo en tu ejemplo.

Editar 2: utilice el mapa zip cuando realmente necesite un mapa, por ejemplo, para un rápido acceso basado en claves aleatorias.

+1

Pereza ... excelente observación! – progo

3

(kv zipmap) realiza dos SEQs y devuelve mapa (y no preserva orden de los elementos)

(mapa vectorial s1 s2 ...) toma cualquier conteo de SEQs y devuelve siguientes

utilizar la primera, cuando se quiere comprimir dos SEQs en un mapa.

utilice el segundo, cuando desee aplicar vector (o lista o cualquier otro formulario de creación de seq) a varios seqs.

hay una cierta similitud con la opción de "intercalar" al imprimir varias copias de un documento :)

+0

+1 para cotejar ... ¡una bonita metáfora visual! – mikera

3

Los dos pueden parecer similares, pero en realidad son muy diferentes.

  • zipmap crea un mapa
  • (map vector ...) crea un LazySeq de n-tuplas (vectores de tamaño n)

Estos son dos estructuras de datos muy diferentes. Si bien una secuencia diferida de 2 tuplas puede parecer similar a un mapa, se comportan de manera muy diferente.

Digamos que estamos mapeando dos colecciones, coll1 y coll2. Considere el caso coll1 tiene elementos duplicados. La salida de zipmap solo contendrá el valor correspondiente a la última aparición de las claves duplicadas en coll1. La salida de (map vector ...) contendrá 2 tuplas con todos los valores de las claves duplicadas.

Un ejemplo sencillo REPL:

=> (zipmap [:k1 :k2 :k3 :k1] [1 2 3 4]) 
{:k3 3, :k2 2, :k1 4} 

=>(map vector [:k1 :k2 :k3 :k1] [1 2 3 4]) 
([:k1 1] [:k2 2] [:k3 3] [:k1 4]) 

Con esto en mente, es trivial para ver el peligro en asumir lo siguiente:

Pero básicamente - aparte de la orden de la resultante pares: estos dos métodos son equivalentes, porque el mapa seq'd se convierte en una secuencia de vectores.

El mapa seq'd se convierte en una secuencia de vectores, pero no necesariamente la misma secuencia de vectores como los resultados de (map vector ...)

Para completar, aquí están los vectores seq'd ordenados:

=> (sort (seq (zipmap [:k1 :k2 :k3 :k1] [1 2 3 4]))) 
([:k1 4] [:k2 2] [:k3 3]) 

=> (sort (seq (map vector [:k1 :k2 :k3 :k1] [1 2 3 4]))) 
([:k1 1] [:k1 4] [:k2 2] [:k3 3]) 

creo que lo más cerca que podemos llegar a una afirmación como la anterior es:

el set del resultado de (zip map coll1 coll2) será igual a el set del resultado de (map vector coll1 coll2) si coll1 es en sí set.

Eso es una gran cantidad de calificadores para dos operaciones que son supuestamente muy similares. Es por eso que se debe tener especial cuidado al decidir cuál usar. Son muy diferentes, sirven para diferentes propósitos y no deben usarse indistintamente.

Cuestiones relacionadas