Search code examples
clojureclojurescript

Clojure filter by id the nested map in a vector


In the vector and map data example:

        [{:id 2, 
        :codigo "2", 
        :subcats 
            [{:id 3, 
              :codigo "3", 
              :subcats [], 
              :slug "pens-ss", 
              :foto nil, 
              :parent 2}
             {:id 4, 
              :codigo "44", 
              :subcats [], 
              :slug "rotula", 
              :foto nil, 
              :parent 2}
             {:id 5, 
              :codigo "hand", 
              :subcats 
                  [{:id 6, 
                      :codigo "caba", 
                      :subcats [], 
                      :slug "caballetes",
                      :foto nil, 
                      :parent 5}
                   {:id 7, 
                      :codigo "Carton", 
                      :subcats 
                           [{:id 9, 
                             :codigo "ooo", 
                             :subcats [], 
                             :slug "carton-piedra-el-nuevo", 
                             :parent 7}], 
                      :slug "cartoncillos", 
                      :foto nil, 
                      :parent 5}],
               :slug "hands", 
               :foto nil, 
               :padre 2}], 
        :slug "paper",
        :foto nil, 
        :padre nil}]

I can filter the first level of id, but can't filter the nested "subcats" by id. How to filter the nested map inside a vector without "for"?. I need get the nesteds map, example, id = 5 return all subcats:

(filter #(= (:id %) 5 ) @cats)

Finding by id 5, I want to return this:

             {:id 5, 
              :codigo "hand", 
              :subcats 
                  [{:id 6, 
                      :codigo "caba", 
                      :subcats [], 
                      :slug "caballetes",
                      :foto nil, 
                      :parent 5}
                   {:id 7, 
                      :codigo "Carton", 
                      :subcats 
                           [{:id 9, 
                             :codigo "ooo", 
                             :subcats [], 
                             :slug "carton-piedra-el-nuevo", 
                             :parent 7}], 
                      :slug "cartoncillos", 
                      :foto nil, 
                      :parent 5}],
               :slug "hands", 
               :foto nil, 
               :padre 2}

Solution

  • Given a root node of

    (def root {:id 2, 
            :codigo "2", 
            :subcats 
                [{:id 3, 
                  :codigo "3", 
                  :subcats [], 
                  :slug "pens-ss", 
                  :foto nil, 
                  :parent 2}
                 {:id 4, 
                  :codigo "44", 
                  :subcats [], 
                  :slug "rotula", 
                  :foto nil, 
                  :parent 2}
                 {:id 5, 
                  :codigo "hand", 
                  :subcats 
                      [{:id 6, 
                          :codigo "caba", 
                          :subcats [], 
                          :slug "caballetes",
                          :foto nil, 
                          :parent 5}
                       {:id 7, 
                          :codigo "Carton", 
                          :subcats 
                               [{:id 9, 
                                 :codigo "ooo", 
                                 :subcats [], 
                                 :slug "carton-piedra-el-nuevo", 
                                 :parent 7}], 
                          :slug "cartoncillos", 
                          :foto nil, 
                          :parent 5}],
                   :slug "hands", 
                   :foto nil, 
                   :padre 2}], 
            :slug "paper",
            :foto nil, 
            :padre nil})
    

    you can get a sequence of all the nodes using tree-seq:

    (tree-seq map? :subcats root)
    

    then you can find the node you need by :id:

    (first (filter #(= 5 (:id %)) (tree-seq map? :subcats root)))
    

    If the data returned is a sequence at the top level, you can use mapcat to retrieve all the nodes in the forest:

    (def root [{:id 2, ...}])
    
    (mapcat #(tree-seq map? :subcats %) root)