0
votes

Regroupement et fusion par valeur à l'aide de clojure?

J'ai un ensemble de données comme celui-ci

{
  "target_groups": [
    {
      "target_group_id": "1234",
      "target_group_name": "abc",
      "targets": [
        {
          "target_id": "456",
          "target_name": "john"
        },
        {
          "target_id": "789",
          "target_name": "doe"
        }
      ]
    },
    {
      "target_group_id": "56789",
      "target_group_name": "cdes",
      "targets": [
        {
          "target_id": "0987",
          "target_name": "john"
        }
      ]
    }
  ]
}

et je souhaite effectuer une transformation en regroupant et en fusionnant les données par ID de groupe cible afin que la cible du même target_group_id soit ajoutée au groupe cible existant et changer la racine clé des données de "data" en "target_groups"

{
  "data": [
    {
      "target_group_id": "1234",
      "target_group_name": "abc",
      "targets": [
        {
          "target_id": "456",
          "target_name": "john"
        }
      ]
    },
    {
      "target_group_id": "56789",
      "target_group_name": "cdes",
      "targets": [
        {
          "target_id": "0987",
          "target_name": "john"
        }
      ]
    },
    {
      "target_group_id": "1234",
      "target_group_name": "abc",
      "targets": [
        {
          "target_id": "789",
          "target_name": "doe"
        }
      ]
    }
  ]
}

y a-t-il un moyen efficace de le faire avec clojure depuis mon code original en utilisant php et en prendre beaucoup de "if-clause" et "foreach"? merci ...


1 commentaires

J'ai répondu, mais j'ai réalisé que ma réponse avait un défaut, alors éditer maintenant


3 Réponses :


0
votes

Voici comment je l'aborderais:

    (is= data-edn
      {:data
       [{:target_group_id   "1234",
         :target_group_name "abc",
         :targets           [{:target_id "456", :target_name "john"}]}
        {:target_group_id   "56789",
         :target_group_name "cdes",
         :targets           [{:target_id "0987", :target_name "john"}]}
        {:target_group_id   "1234",
         :target_group_name "abc",
         :targets           [{:target_id "789", :target_name "doe"}]}]})

    (is= d2
      {"1234"
       [{:target_group_id   "1234",
         :target_group_name "abc",
         :targets           [{:target_id "456", :target_name "john"}]}
        {:target_group_id   "1234",
         :target_group_name "abc",
         :targets           [{:target_id "789", :target_name "doe"}]}],
       "56789"
       [{:target_group_id   "56789",
         :target_group_name "cdes",
         :targets           [{:target_id "0987", :target_name "john"}]}]})

    (is= d3
      [{:tgt-group-id   "1234",
        :tgt-group-name "abc",
        :targets-all    [[{:target_id "456", :target_name "john"}]
                         [{:target_id "789", :target_name "doe"}]]}
       {:tgt-group-id   "56789",
        :tgt-group-name "cdes",
        :targets-all    [[{:target_id "0987", :target_name "john"}]]}]) ))

avec transformation:

(dotest
  (let [data-edn (t/json->edn
                   (ts/quotes->double data-json))
        d2       (t/it-> data-edn
                   (:data it) ; unnest from :data key
                   (group-by :target_group_id it ) )
        d3       (t/forv [[tgt-id entries] d2]
                   {:tgt-group-id   tgt-id
                    :tgt-group-name (:target_group_name (first entries))
                    :targets-all    (mapv :targets entries)}) ]

et résultats / tests:

XXX


0 commentaires

0
votes

En utilisant uniquement le core clojure (avec la bibliothèque data.json).

Premièrement, acquérez et développez nos données:

(def output (->> data
                 (group-by #(get % "target_group_id"))
                 vals
                 (map #(reduce concat-targets %))
                 (assoc {} "target_groups")
                 clojure.data.json/write-str))

Lorsque nous adressons des groupes de cibles, nous vont avoir besoin de les concaténer. Je faisais cela en ligne, mais cela semble compliqué dans la réduction, alors voici une fonction d'aide:

(defn concat-targets [acc item]
  (update acc "targets" concat (item "targets")))

Alors faisons le travail!

(def data (-> "grouping-and-merging.json"
              slurp
              clojure.data.json/read-str 
              (get "data")))


0 commentaires

0
votes

Une autre façon de faire la transformation:

(def merge-vector
  (partial apply
           merge-with
           (fn [& xs] (if (every? vector? xs) (apply concat xs) (last xs)))))

La structure de données intermédiaire est une séquence de set indexée par identifiant de groupe et nom de groupe (comme en utilisant group-by ). Ie

(-> "data.json"
    slurp
    json/read-str
    (get "data")
    (set/index ["target_group_id" "target_group_name"])
    vals)

;; =>
(#{{"target_group_id" "1234",
    "target_group_name" "abc",
    "targets" [{"target_id" "789", "target_name" "doe"}]}
   {"target_group_id" "1234",
    "target_group_name" "abc",
    "targets" [{"target_id" "456", "target_name" "john"}]}}
 #{{"target_group_id" "56789",
    "target_group_name" "cdes",
    "targets" [{"target_id" "0987", "target_name" "john"}]}})

Les cibles (qui est un vecteur ) sont alors concat avec merge-vector:

{"target_groups" (map merge-vector (-> "data.json"
                                       slurp
                                       json/read-str
                                       (get "data")
                                       (set/index ["target_group_id" "target_group_name"])
                                       vals))}

;; =>
{"target_groups"
 ({"target_group_id" "1234",
   "target_group_name" "abc",
   "targets"
   ({"target_id" "789", "target_name" "doe"}
    {"target_id" "456", "target_name" "john"})}
  {"target_group_id" "56789",
   "target_group_name" "cdes",
   "targets" [{"target_id" "0987", "target_name" "john"}]})}


0 commentaires