Katta klojru xaritasida keraksiz kalitlarni filtrlash

Men Clojureda chindan ham katta eshaklarni o'z ichiga olgan xaritani oldim. Keyinchalik ochko'zliklarni ochish uchun eng odatiy usulni izlayapman. (Ha, bu jodugarlik xizmati orqa tomonda ishlaydi).

Ma'lumotlar bazasi quyidagicha ko'rinadi:

(def data
  {:a 1
   :b 2
   :c 3
   :d [{:e 5}
       {:f 6
        :g {
            :h 8
            :i 9
            :j 10}
        :l [{
             :m 11
             :n 12
             :p {:q 13
                 :r 14
                 :s 15
                 }}
            {:m 16
             :n 17
             :p {:q 18
                 :r 19
                 :s 20
                 }}]}]})

As you can see, I got a map with keys, whereby some keys got lists with maps, which have some lists again...so I know -> not pretty.

BUT ... Men xohlagan ma'lumotni ta'riflashning ba'zi usullari, men istamagan har bir tugmachani filtrlash kerakmi?

Rahmat

2
Kirishdan nimani olishni xohlaysiz? Katta o'lchovli xaritani joylashtirdingiz va faqatgina ba'zi qismini istaysiz, deb aytdim. Qaysi narsalarga ham e'tibor berasiz?
qo'shib qo'ydi muallif amalloy, manba
Ehtimol, men bu eng yaxshi yo'ldirmi? Bundan tashqari, men buni ierativ tarzda amalga oshirishim mumkin ... lekin, ehtimol, bir diagramma yozilishi mumkin, men bu ma'lumotlarga qanday qilib murojaat qilishim mumkin.
qo'shib qo'ydi muallif Tobias K., manba

5 javoblar

clojure.walk ishlatadigan har qanday tashqi libosni ishlatmasdan, yana bir tarzda:

(defn remove-deep [key-set data]
  (clojure.walk/prewalk (fn [node] (if (map? node)
                                     (apply dissoc node key-set)
                                     node))
                        data))


user> (remove-deep [:i :l] data)
;;=> {:a 1, :b 2, :c 3, :d [{:e 5} {:f 6, :g {:h 8, :j 10}}]}

user> (remove-deep [:f :p] data)
;;=> {:a 1, :b 2, :c 3, :d [{:e 5} {:g {:h 8, :i 9, :j 10}, :l [{:m 11, :n 12} {:m 16, :n 17}]}]}

Old/postwalk sizda mavjud bo'lgan aniq foydalanish holatlari uchun: heterojen koleksiyani pastga yuring, kerak bo'lganda qiymatlarni o'zgartiring

7
qo'shib qo'ydi
Ha, bu 2-veksni (MapEntry juftligini) qidirishdan ko'ra oddiy.
qo'shib qo'ydi muallif Alan Thompson, manba
@slipset, tree-seq - o'tish uchun yaxshi, lekin modifikatsiya qilish uchun foydasiz
qo'shib qo'ydi muallif leetwinski, manba

Eng oddiy clojure.walk/postwalk dan foydalanish uchun . Men "sizni faqat f: f ning farzandi bo'lganda olib tashlash" kabi har qanday kalit birikmalaridan xavotirlanishingizga hojat yo'q deb o'ylayman.

Mana bir misol:

(ns tst.demo.core
  (:use demo.core tupelo.core tupelo.test)
  (:require [clojure.walk :as walk]))

(def data
  {:a 1
   :b 2
   :c 3
   :d [{:e 5}
       {:f 6
        :g {
            :h 8
            :i 9
            :j 10}
        :l [{
             :m 11
             :n 12
             :p {:q 13
                 :r 14
                 :s 15
                 }}
            {:m 16
             :n 17
             :p {:q 18
                 :r 19
                 :s 20
                 }}]}]})

(defn remove-keys [data keys]
  (let [proc-node  (fn [node]
                     (spyx node))
        result (walk/postwalk proc-node data) ]
    (spyx-pretty result)))

(def bad-keys #{:b :f :i :p :n})

(dotest
  (remove-keys data bad-keys))

Bu postwalk ning yinelanadigan ishlashini ko'rsatadi,

Testing tst.demo.core
node => :a
node => 1
node => [:a 1]
node => :b
node => 2
node => [:b 2]
node => :c
node => 3
node => [:c 3]
node => :d
node => :e
node => 5
node => [:e 5]
node => {:e 5}
node => :f
node => 6
node => [:f 6]
node => :g
node => :h
node => 8
node => [:h 8]
node => :i
node => 9
node => [:i 9]
node => :j
node => 10
node => [:j 10]
node => {:h 8, :i 9, :j 10}
node => [:g {:h 8, :i 9, :j 10}]
node => :l
node => :m
node => 11
node => [:m 11]
node => :n
node => 12
node => [:n 12]
node => :p
node => :q
node => 13
node => [:q 13]
node => :r
node => 14
node => [:r 14]
node => :s
node => 15
node => [:s 15]
node => {:q 13, :r 14, :s 15}
node => [:p {:q 13, :r 14, :s 15}]
node => {:m 11, :n 12, :p {:q 13, :r 14, :s 15}}
node => :m
node => 16
node => [:m 16]
node => :n
node => 17
node => [:n 17]
node => :p
node => :q
node => 18
node => [:q 18]
node => :r
node => 19
node => [:r 19]
node => :s
node => 20
node => [:s 20]
node => {:q 18, :r 19, :s 20}
node => [:p {:q 18, :r 19, :s 20}]
node => {:m 16, :n 17, :p {:q 18, :r 19, :s 20}}
node => [{:m 11, :n 12, :p {:q 13, :r 14, :s 15}} {:m 16, :n 17, :p {:q 18, :r 19, :s 20}}]
node => [:l [{:m 11, :n 12, :p {:q 13, :r 14, :s 15}} {:m 16, :n 17, :p {:q 18, :r 19, :s 20}}]]
node => {:f 6, :g {:h 8, :i 9, :j 10}, :l [{:m 11, :n 12, :p {:q 13, :r 14, :s 15}} {:m 16, :n 17, :p {:q 18, :r 19, :s 20}}]}
node => [{:e 5} {:f 6, :g {:h 8, :i 9, :j 10}, :l [{:m 11, :n 12, :p {:q 13, :r 14, :s 15}} {:m 16, :n 17, :p {:q 18, :r 19, :s 20}}]}]
node => [:d [{:e 5} {:f 6, :g {:h 8, :i 9, :j 10}, :l [{:m 11, :n 12, :p {:q 13, :r 14, :s 15}} {:m 16, :n 17, :p {:q 18, :r 19, :s 20}}]}]]
node => {:a 1, :b 2, :c 3, :d [{:e 5} {:f 6, :g {:h 8, :i 9, :j 10}, :l [{:m 11, :n 12, :p {:q 13, :r 14, :s 15}} {:m 16, :n 17, :p {:q 18, :r 19, :s 20}}]}]}
result => 
{:a 1,
 :b 2,
 :c 3,
 :d
 [{:e 5}
  {:f 6,
   :g {:h 8, :i 9, :j 10},
   :l
   [{:m 11, :n 12, :p {:q 13, :r 14, :s 15}}
    {:m 16, :n 17, :p {:q 18, :r 19, :s 20}}]}]}

Siz xaritalarni avval [: n 17] kabi kalit-qiymat juftligini vektorlariga aylantirganini ko'rishingiz mumkin. Shunday qilib, siz 2-vekkaga ega bo'lgach, birinchi elementni ko'rib chiqing va uni yoqtirmasangiz nil funksiyasini qaytaring:

(defn len-2-vec? [node]
  (and (sequential? node)
    (= 2 (count node))))

(defn remove-keys [data bad-keys]
  (let [proc-node (fn [node]
                    (if (and (len-2-vec? node)
                          (contains? bad-keys (first node)))
                      (do
                        (spyx :removed node)
                        nil)
                      node))
        result (walk/postwalk proc-node data) ]
    (spyx-pretty result)))

(def bad-keys #{:b :f :i :p :n})

(dotest
  (remove-keys data bad-keys))

va chiqish:

Testing tst.demo.core
:removed    node => [:b 2]
:removed    node => [:f 6]
:removed    node => [:i 9]
:removed    node => [:n 12]
:removed    node => [:p {:q 13, :r 14, :s 15}]
:removed    node => [:n 17]
:removed    node => [:p {:q 18, :r 19, :s 20}]

(remove-keys data bad-keys) => 
{:a 1, 
 :c 3, 
 :d [{:e 5} 
     {:g {:h 8, 
          :j 10}, 
      :l [{:m 11}
          {:m 16}]}]}

Ran 2 tests containing 0 assertions.
0 failures, 0 errors.
Clojure CheatSheet ni unutmang.

Here is the doc for spyx.

4
qo'shib qo'ydi

If you want to filter for the top-level keys only you can use select-keys

Chuqur ichki o'rnatilgan kalitlarni o'chirish uchun tomoshabin foydalanishingiz mumkin. Masalan, : d ostidagi vektordagi barcha elementlar ostida : h ostidagi barcha qiymatlarni olib tashlash uchun : g

user> (setval [:d ALL :g :h] NONE data)
4
qo'shib qo'ydi

Bu talabga qaraganda ko'proq "qo'lda olib tashlash" dan foydalanishi mumkin, ammo oddiy recursiv funktsiya bu yaxshi ishlaydi:

(defn filter-nested [root keys-to-remove]
  (let [should-remove? (set keys-to-remove)

        ; A recursive function to search through the map
        f (fn rec [node]
            (reduce-kv (fn [acc k v]
                         (cond
                           ; If it's in the set, remove the key from the node
                           (should-remove? k) (dissoc acc k)

                           ; If the value is a map, recursively search it too
                           (map? v) (assoc acc k (rec v))

                           ; If it's a vector, map a recursive call over the vector
                           (vector? v) (assoc acc k (mapv rec v))

                           ; Else do nothing
                           :else acc))
                       node
                       node))]
    (f root)))

(filter-nested data #{:l})
=> {:a 1, :b 2, :c 3, :d [{:e 5} {:f 6, :g {:h 8, :i 9, :j 10}}]}

Izohli izohlarni hisobga olganingizdan so'ng, u ko'rinadigan darajada katta emas. f (ichki rec ), kalitlar ro'yxatida bo'lganda topilgan xaritada dissoc ning kalitlarini o'zida saqlab turadigan funksiya. Topilgan qiymat bir xarita yoki vektor bo'lsa, u ham ularni qidirish uchun takrorlanadi.

3
qo'shib qo'ydi

Qora ro'yxatni ishlatish o'rniga biz oq ro'yxatga olishni xohladik. Ishlab chiqarishda qora ro'yxat bilan ishlash yaxshi fikr emas - agar biron-bir sababga ko'ra javob obyekti uzaytirilsa. Shuning uchun biz https://github.com/metosin/spec-tools dan < kodi> strip-extra-keys-transformer kabi:

(ns sexy.helper.transformer
  (:require [spec-tools.core :as st]
            [spec-tools.data-spec :as ds]))

(def my-abc {:a "12345"
               :b "00529"
               :c [{:d "Kartoffel"
                    :e 5}
                   {:d "Second Item"
                    :e 9999}]})

(def the-abc
  {:a string?
   :c [{:d string?}]})

(def abc-spec
  (ds/spec ::abc the-abc))

(st/conform abc-spec my-abc st/strip-extra-keys-transformer)
1
qo'shib qo'ydi