如何将数据附加到clojure地图的所有叶节点?

时间:2015-07-16 10:13:09

标签: data-structures clojure

我在clojure中有一个地图数据结构:

{:category_id 1,:name“ELECTRONICS”,:lft 1,:rgt 20,:children [{:category_id 6,:name“PORTABLE ELECTRONICS”,:lft 10,:rgt 19,:children [{:children [{:rgt 13,:lft 12,:name“FLASH”,:category_id 8}],:category_id 7,:name“MP3 PLAYERS”,:lft 11,:rgt 14} {:rgt 18, :lft 17,:名称“2 WAY RADIOS”,:category_id 10} {:rgt 16,:lft 15,:name“CD PLAYERS”,:category_id 9}]} {:children [{:rgt 6,:lft 5 ,:name“LCD”,:category_id 4} {:rgt 8,:lft 7,:name“PLASMA”,:category_id 5} {:rgt 4,:lft 3 ,: name“TUBE”,:category_id 3}] ,:rgt 9,:lft 2 ,: name“TELEVISIONS”,:category_id 2}]}

我想将一些数据(与类别相关联的产品)附加到作为产品类别的所有叶节点,以便它看起来像这样:

{:category_id 1,:name“ELECTRONICS”,:lft 1,:rgt 20,:children [{:category_id 6,:name“PORTABLE ELECTRONICS”,:lft 10,:rgt 19,:children [{:children [{:rgt 13,:lft 12,:name“FLASH”,:category_id 8}],:category_id 7,:name“MP3 PLAYERS”,:lft 11,:rgt 14:products [{:name “SONY MP3 PLAYER”} {:name“SONY MP3 PLAYER 2”}}} {:rgt 18,:lft 17,:name“2 WAY RADIOS”,:category_id 10} {:rgt 16,:lft 15,:name “CD播放器”,:category_id 9}]} {:children [{:rgt 6,:lft 5,:name“LCD”,:category_id 4} {:rgt 8,:lft 7,:name“PLASMA”,: category_id 5} {:rgt 4,:lft 3,:name“TUBE”,:category_id 3}],:rgt 9,:lft 2,:name“TELEVISIONS”,:category_id 2}]}

我已将两个产品添加到叶节点“MP3播放器”

如何使用clojure实现这一目标?如果不是clojure,我可以用任何其他编程语言获得解决方案吗?像Python等。?

2 个答案:

答案 0 :(得分:2)

假设您不知道您的类别位于层次结构中的哪个位置,您可以使用此方法:

(use 'clojure.walk)

(defn add-to-category
  [catalog cat-id product]
  (postwalk (fn [x]
              (if (and (map? x)
                       (= (:category_id x) cat-id))
                (update-in x [:products] conj product)
                x))
            catalog))

这是您的初始地图:

(def my-catalog {:children
 [{:children
   [{:children [{:name "FLASH", :lft 12, :category_id 8, :rgt 13}],
     :name "MP3 PLAYERS",
     :lft 11,
     :category_id 7,
     :rgt 14}
    {:name "2 WAY RADIOS", :lft 17, :category_id 10, :rgt 18}
    {:name "CD PLAYERS", :lft 15, :category_id 9, :rgt 16}],
   :name "PORTABLE ELECTRONICS",
   :lft 10,
   :category_id 6,
   :rgt 19}
  {:children
   [{:name "LCD", :lft 5, :category_id 4, :rgt 6}
    {:name "PLASMA", :lft 7, :category_id 5, :rgt 8}
    {:name "TUBE", :lft 3, :category_id 3, :rgt 4}],
   :name "TELEVISIONS",
   :lft 2,
   :category_id 2,
   :rgt 9}],
 :name "ELECTRONICS",
 :lft 1,
 :category_id 1,
 :rgt 20}

调用为:

(add-to-category my-catalog 7 {:name "SONY MP3 PLAYER 2"})

答案 1 :(得分:-1)

这看起来像是update-in的工作。

(def categories {:category_id 1, :name "ELECTRONICS", :lft 1, :rgt 20, :children [{:category_id 6, :name "PORTABLE ELECTRONICS", :lft 10, :rgt 19, :children [{:children [{:rgt 13, :lft 12, :name "FLASH", :category_id 8}], :category_id 7, :name "MP3 PLAYERS", :lft 11, :rgt 14} {:rgt 18, :lft 17, :name "2 WAY RADIOS", :category_id 10} {:rgt 16, :lft 15, :name "CD PLAYERS", :category_id 9}]} {:children [{:rgt 6, :lft 5, :name "LCD", :category_id 4} {:rgt 8, :lft 7, :name "PLASMA", :category_id 5} {:rgt 4, :lft 3, :name "TUBE", :category_id 3}], :rgt 9, :lft 2, :name "TELEVISIONS", :category_id 2}]})

(update-in categories [:children 0 :children 0 :products]
                      conj {:name "SONY MP3 PLAYER"} {:name "SONY MP3 PLAYER 2"})

;; Returns a similar giant map. Here with clojure.pprint/pprint formatting:
{:category_id 1,
 :name "ELECTRONICS",
 :lft 1,
 :rgt 20,
 :children
 [{:category_id 6,
   :name "PORTABLE ELECTRONICS",
   :lft 10,
   :rgt 19,
   :children
   [{:products ({:name "SONY MP3 PLAYER 2"} {:name "SONY MP3 PLAYER"}),
     :children [{:rgt 13, :lft 12, :name "FLASH", :category_id 8}],
     :category_id 7,
     :name "MP3 PLAYERS",
     :lft 11,
     :rgt 14}
    {:rgt 18, :lft 17, :name "2 WAY RADIOS", :category_id 10}
    {:rgt 16, :lft 15, :name "CD PLAYERS", :category_id 9}]}
  {:children
   [{:rgt 6, :lft 5, :name "LCD", :category_id 4}
    {:rgt 8, :lft 7, :name "PLASMA", :category_id 5}
    {:rgt 4, :lft 3, :name "TUBE", :category_id 3}],
   :rgt 9,
   :lft 2,
   :name "TELEVISIONS",
   :category_id 2}]}

如果您特别需要:products作为向量,那么您希望代替conj使用创建向量的函数(如果它已通过nil }作为第一个参数。 conj should work this way starting in 1.7,但我必须提供的测试时间早于此。