【问题标题】:How to append data to all the leaf nodes of a clojure map?如何将数据附加到 clojure 映射的所有叶节点?
【发布时间】:2015-07-16 10:13:09
【问题描述】:

我在 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, :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 "电视", :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 PLAYERS”中添加了两个产品

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

【问题讨论】:

  • 请做一个更简单的例子。很难说你的问题的哪一部分是重要的,哪一部分只是噪音。

标签: data-structures clojure


【解决方案1】:

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

(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"})

【讨论】:

  • 非常简洁的答案@Guillermo
【解决方案2】:

这看起来像是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,则该函数会生成一个向量。 conjshould work this way starting in 1.7,但我必须亲手测试的东西比这更老。

【讨论】:

  • 非常感谢您的回答。但我想以通用方式附加数据,即我有一个产品向量 [{:rgt 6, :lft 5, :name "LCD", :category_id 4, :pro_name "sony bravia"} {:rgt 14, :lft 11, :name "MP3 PLAYERS", :category_id 7, :pro_name "sony mp3 player"}] 存储一些属于特定类别的产品。所以我想遍历地图和产品向量并附加数据。
  • 啊。所以你需要确定一个具有相同:category_id的类别的路径,然后在那里添加产品?或许可以为此使用clojure.zip。稍后我可能会再看看。
  • 我认为您需要澄清您的问题,例如包括示例产品向量并相应地更新您的示例。还请说明您是否只想匹配category_id 以及产品类别是否可能嵌套。请也适当地格式化代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-26
  • 2020-07-04
  • 1970-01-01
  • 2019-06-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多