2011-03-23 7 views
9

¿Cuáles son las maneras concisas/elegantes de poner en un mapa los pares clave-valor para los que las condiciones correspondientes son verdaderas?Poniendo pares clave-valor en el mapa condicionalmente, ¿cuáles son las formas concisas?

Eso es traducir

[condition1 condition2 ...] [key1 val1 key2 val2 ...] 

o

[condition1 condition2 ...] [key1 key2 ...] [val1 val2 ...] 

o

[condition1 key1 val1 condition2 key2 val2...] 

en

{key-for-true-condition1 val-for-true-condition1, key-for-true-condition2 val-for-true-condition2...} 

Creo que usar "reducir" con "si" en su lambda pero interesado en formas más concisas/bellas/elegantes/idiomáticas.

Respuesta

6
(into {} (for [[c k v] (partition 3 coll) :when c] 
    [k v])) 

Basado en la versión 'for' de Kintaro pero un poco más corto.

1
(def coll [true :key1 "value1" false :key2 "value2" true :key3 "value3"]) 

(defn testpair [[cond key val]] 
    (when cond 
     {key val})) 

(apply merge (map testpair (partition 3 coll))) 
=> {:key3 "value3", :key1 "value1"} 

Esto sería de una manera, pero si desea otras combinaciones de clave de condición y valor, debe cambiar el código. No mencionaste que una bruja sería la mejor.

Editar: porque es el primero en su lista

(def conditions [true false true]) 
(def keyval [:key1 "value1" :key2 "value2" :key3 "value3"]) 

(defn testpair [cond [key val]] 
    (when cond 
     {key val})) 

(apply merge (map testpair conditions (partition 2 keyval))) 

Porque es divertido :)

(def conditions [true false true]) 
(def keys [:key1 :key2 :key3]) 
(def vals ["value1" "value1" "value3"]) 


(defn testpair [cond key val] 
    (when cond 
     {key val})) 

(apply merge (map testpair conditions keys vals)) 
3

para ser honesto OMI, la versión con reduce y if ya son los más elegantes y idiomático ver comentario de nickik a continuación.

(def coll [true :a "v1" false :b "v2" true :c "v3"]) 

(reduce (fn [a [c k v]] (if c (assoc a k v) a)) {} (partition 3 coll)) 

Aquí es una versión con el de la comprensión para el tercer caso:

(apply array-map (flatten (for [[c k v] (partition 3 coll) :when c] 
          [k v]))) 

Editar:

Para el segundo caso se lo convierte en el tercer caso haciendo:

(def c [true false true]) 
(def k [:a :b :c]) 
(def v ["v1" "v2" "v3"]) 

(def coll (interleave c k v)) 

Pero creo que la versión map de nickik es mejor aquí.

+3

Mhh agradable. Se me ocurrió algo un poco mejor (creo): (en {} (para [[ckv] (partición 3 coll): cuando c] [kv])) – nickik

+0

ah sabía que hay una mejor manera de obtener un mapa de una lista de vectores de valores-clave :) – Kintaro

+0

Creo que el ejemplo de reducción es malo porque es realmente difícil de leer. Usar "para" es mejor en este caso. – nickik

2

yo primero pensar en ello como la manera de ser mejor asignar sus operaciones funcionales sobre un arroyo:

  1. Grupo condiciones/clave/valor en un trozo
  2. trozos de filtro, en la condición no es cierto
  3. gota las condiciones
  4. Acoplar los trozos
  5. crear un mapa a partir del resultado

que se parece a:

(def coll [true :a "v1" false :b "v2" true :c "v3"]) 

(apply hash-map 
    (flatten 
    (map #(drop 1 %) 
     (filter #(first %) 
     (partition 3 coll))))) 

O si se siente filiforme:

(->> coll 
    (partition 3) 
    (filter #(first %)) 
    (map #(drop 1 %)) 
    flatten 
    (apply hash-map)) 

no estoy seguro de que esto es elegante o concisa, pero yo creo que es fácil de leer. Tenga en cuenta que si usted trata con frecuencia con los datos en esta forma, es posible que los pasos como (partición 3 coll) o (primera%) podrían ser funciones reutilizables útiles en su propio derecho que conducen a algo como:

(defn condition-group [coll] (partition 3 coll)) 
(defn condition [group] (first group)) 
(defn but-condition [group] (drop 1 group)) 
(defn kv-map [kv-pairs] (apply hash-map (flatten kv-pairs))) 

(->> coll 
    condition-group 
    (filter condition) 
    (map but-condition) 
    kv-map) 
Cuestiones relacionadas