5 votes

Puis-je "transposer" une liste de cartes en une carte de listes en Clojure ?

Bonjour huys : Je souhaite calculer une "moyenne" pour toutes les valeurs d'une carte. disons que j'ai une liste de cartes :

[{"age" 2 "height" 1 "weight" 10},
{"age" 4 "height" 4 "weight" 20},
{"age" 7 "height" 11 "weight" 40}]

Le résultat que je souhaite obtenir est le suivant

{"age 5 "height" 5 ....}

///Ce qui suit sont les divagations de mon cerveau, c'est-à-dire la façon dont je pourrais imaginer que cela fonctionne en Clojure... à ne pas prendre trop au sérieux.

transposer la liste :

  {"age" [2 4 7] "height" [1 4 11] } 

et je pourrais alors simplement faire quelque chose comme (encore une fois, j'invente une fonction appelée freduce ici)

  (freduce average (vals (map key-join list)))

pour obtenir

{"age" 5 "weight" 10 "height" 7}

6voto

Alex Taggart Points 5733

Créer la carte des vecteurs :

(reduce (fn \[m \[k v\]\]
          (assoc m k (conj (get m k \[\]) v)))
        {}
        (apply concat list-of-maps))

Créer la carte des moyennes :

(reduce (fn \[m \[k v\]\]
          (assoc m k (/ (reduce + v) (count v))))
        {}
        map-of-vectors)

5voto

mange Points 2366

Jetez un coup d'œil à fusionner avec

Voici ma tentative de code réel :

(let [maps [{"age" 2 "height" 1 "weight" 10},
            {"age" 4 "height" 4 "weight" 20},
            {"age" 7 "height" 11 "weight" 40}]]
  (->> (apply merge-with #(conj %1 %2)
             (zipmap (apply clojure.set/union (map keys maps))
                     (repeat [])) ; set the accumulator
             maps)
       (map (fn [[k v]] [k (/ (reduce + v) (count v))]))
       (into {})))

4voto

amalloy Points 29125

Voici une solution assez verbeuse. J'espère que quelqu'un pourra trouver quelque chose de mieux :

(let [maps [{"age" 2 "height" 1 "weight" 10},
            {"age" 4 "height" 4 "weight" 20},
            {"age" 7 "height" 11 "weight" 40}]
      ks (keys (first maps))
      series-size (count maps)
      avgs (for [k ks]
             (/ (reduce +
                        (for [m maps]
                          (get m k)))
                series-size))]
  (zipmap ks avgs))

2voto

BLUEPIXY Points 18514
(defn key-join [map-list]
  (let [keys (keys (first map-list))]
       (into {} (for [k keys] [k (map #(% k) map-list)]))))
(defn mapf [f map]
  (into {} (for [[k v] map ] [k (f v)])))
(defn average [col]
  (let [n (count col)
        sum (apply + col)]
       (/ sum n)))

DEMO

user=> (def data-list [{"age" 2 "height" 1 "weight" 10},
{"age" 4 "height" 4 "weight" 20},
{"age" 7 "height" 11 "weight" 40}])
#'user/data-list
user=> (key-join data-list)
{"age" (2 4 7), "height" (1 4 11), "weight" (10 20 40)}
user=> (mapf average (key-join data-list))
{"age" 13/3, "height" 16/3, "weight" 70/3}

1voto

user499049 Points 336

Voici une autre version qui utilise merge-with sans zipmap.

(let [data [{:a 1 :b 2} {:a 2 :b 4} {:a 4 :b 8}]
           num-vals (count data)]
     (->> data (apply merge-with +) 
          (reduce (fn [m [k v]] (assoc m k (/ v num-vals))) {})))

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X