2012-06-25 4 views
0

Je dois fusionner une collection de tableaux basée sur id.Fusion de tableaux dans Clojure

Exemple de données:

EDIT: (modifié pour correspondre à des structures de données Clojure)

[{:id 1, :region :NA, :name :Test1, :OS :W} 
    {:id 1, :region :EU, :name :Test2, :OS :W} 
    {:id 2, :region :AS, :name :test3, :OS :L} 
    {:id 2, :region :AS, :name :test4, :OS :M}] 

devient:

EDIT: (modifié pour correspondre à des structures de données Clojure)

[{:id 1, :region [:NA :EU], :name [:Test1 :Test2] ,:OS [:W]} 
{:id 2, :region [:AS] :name [:test3 :Test4], :OS [:L :M]}] 

| est le délimiteur (modifiable) Si possible, voudrait aussi l'ordre alphabétique.

+0

Ce ne sont pas valables stru de données Clojure ctures. Ces chaînes sont-elles? Est-ce une question sur l'analyse/manipulation de chaînes dans Clojure? Qu'avez-vous essayé jusqu'ici pour résoudre ce problème? S'il vous plaît fournir des exemples de code. Dans ce formulaire ce n'est pas une bonne question. – Gert

+0

l'intention de la première partie est assez claire, donc j'ai édité les structures. Je ne suis pas sûr de savoir comment interpréter la deuxième partie. –

Répondre

0
(def data 
[{:id 1, :region :NA, :name :Test1, :OS :W} 
    {:id 1, :region :EU, :name :Test2, :OS :W} 
    {:id 2, :region :AS, :name :test3, :OS :L} 
    {:id 2, :region :AS, :name :test4, :OS :M}]) 

(defn key-join 
    "join of map by key , value is distinct." 
    [map-list] 
    (let [keys (keys (first map-list))] 
     (into {} (for [k keys] [k (vec (set (map #(% k) map-list)))])))) 

(defn group-reduce [key map-list] 
    (let [gdata (group-by key map-list)] 
    (into [] (for [[k m] gdata] (let [m (key-join m)](assoc m key ((key m) 0))))))) 



user=> (group-reduce :id data) 
[{:name [:Test2 :Test1], :OS [:W], :region [:EU :NA], :id 1} {:name [:test3 :test4], :OS [:L :M], :region [:AS], :id 2}] 
0

Vous pouvez utiliser une combinaison de fonctions de clojure.set (si vous modifiez le vecteur le plus externe à définir). Plus précisément clojure.set/index semble prometteur.

0

Vous pouvez utiliser la fonction merge-with comme indiqué ci-dessous dans l'exemple.

Tout d'abord, nous définissons quelques fonctions d'aide

(defn collect [& xs] 
    (apply vector (-> xs distinct sort))) 

La fonction collect vérifie que les éléments de xs sont uniques et triés et enfin les retourne dans un vecteur.

(defn merge-keys [k xs] 
    (map #(apply merge-with collect %) (vals (group-by k xs)))) 

merge-keys premiers groupes par les une clé primaire de hachage cartes dans xs (dans votre cas :id), prend chaque liste d'éléments groupés et fusionne les valeurs des touches en utilisant la fonction collect d'en haut.

(def xs [{:id 1, :region :NA, :name :Test1, :OS :W} 
     {:id 1, :region :EU, :name :Test2, :OS :W} 
     {:id 2, :region :AS, :name :test3, :OS :L} 
     {:id 2, :region :AS, :name :test4, :OS :M}]) 

(merge-keys :id xs) 
=> ({:id [1], 
    :region [:EU :NA], 
    :name [:Test1 :Test2], 
    :OS [:W]} 
    {:id [2], 
    :region [:AS], 
    :name [:test3 :test4], 
    :OS [:L :M]}) 

Remarque cependant que même la clé :id a maintenant vecteur associé. Vous pouvez facilement un vecteur par l'introduction d'une déclaration soit if dans collect qui associe une valeur unique à la clé au lieu d'un vecteur ...

(defn collect [& xs] 
    (let [cs (apply vector (-> xs distinct sort))] 
    (if (= 1 (count cs)) (first cs) cs))) 

... ou prendre le résultat de merge-keys et faire

(map #(update-in % [:id] first) result) 

qui ne fera que un vecteur l'entrée carte :id