clojure - 如何按路径过滤 map 内容

标签 clojure

我想选择要保留的深度嵌套 map 的路径。
例如:

{:a 1
 :b {:c [{:d 1 :e 1} 
         {:d 2 :e 2}]
     :f 1}
 :g {:h {:i 4 :j [1 2 3]}}}
我想按路径选择,如下所示:
(select-paths m [[:a] 
                 [:b :c :e]
                 [:b :f]
                 [:g :h :i]])
这将返回
{:a 1
 :b {:c [{:e 1}
         {:e 2}]
     :f 1}
 :g {:h {:i 4}}}
与 Elasticsearch 的 fields 基本相同范围。路径参数的格式可以是别的东西,这只是第一个想法。
我尝试了两种不同的解决方案
  • 遍历整个 map 并检查当前元素的完整路径是否在给定路径中。我不知道如何处理 map 列表,以便将它们保存为 map 列表。
  • 正在创建 select-keys来自给定路径的语句,但我再次遇到了 map 列表的问题 - 特别是试图解决具有某些共同深度的不同深度的路径。

  • 我看着幽灵,但我没有看到任何可以做到这一点的东西。任意 mappostwalk我提出的基于解决方案的解决方案在某些时候变成了令人难以置信的复杂。我一定是在以错误的方式思考这个问题。
    如果有办法用原始 json 来做到这一点,那也很好。甚至是 Java 解决方案。

    最佳答案

    没有简单的方法可以实现您的目标。对 [:b :c] 下的序列隐含的自动处理也是有问题的。
    您可以使用 Tupelo Forest 到达那里。图书馆。见 Lightning Talk video来自 Clojure/Conj 2017。
    我在数据解构方面做了一些额外的工作,您可能会发现构建 tupelo.core/destruct 很有用。宏(参见示例 here )。您可以按照类似的大纲为您的特定问题构建递归解决方案。
    一个相关的项目是 Meander .我已经在我自己的版本上工作,它就像 tupelo.core/destruct 的通用版本.给定这样的数据

    (def skynet-widgets [{:basic-info   {:producer-code "Cyberdyne"}
                          :widgets      [{:widget-code      "Model-101"
                                          :widget-type-code "t800"}
                                         {:widget-code      "Model-102"
                                          :widget-type-code "t800"}
                                         {:widget-code      "Model-201"
                                          :widget-type-code "t1000"}]
                          :widget-types [{:widget-type-code "t800"
                                          :description      "Resistance Infiltrator"}
                                         {:widget-type-code "t1000"
                                          :description      "Mimetic polyalloy"}]}
                         {:basic-info   {:producer-code "ACME"}
                          :widgets      [{:widget-code      "Dynamite"
                                          :widget-type-code "c40"}]
                          :widget-types [{:widget-type-code "c40"
                                          :description      "Boom!"}]}])
    
    您可以使用这样的模板搜索和提取数据:
    
        (let [root-eid (td/add-entity-edn skynet-widgets)
              results  (td/match
                         [{:basic-info   {:producer-code ?}
                           :widgets      [{:widget-code      ?
                                           :widget-type-code wtc}]
                           :widget-types [{:widget-type-code wtc
                                           :description      ?}]}])]
          (is= results
            [{:description "Resistance Infiltrator" :widget-code "Model-101" :producer-code "Cyberdyne" :wtc "t800"}
             {:description "Resistance Infiltrator" :widget-code "Model-102" :producer-code "Cyberdyne" :wtc "t800"}
             {:description "Mimetic polyalloy" :widget-code "Model-201" :producer-code "Cyberdyne" :wtc "t1000"}
             {:description "Boom!" :widget-code "Dynamite" :producer-code "ACME" :wtc "c40"}])))
    
    此代码正在运行(请参阅 here ),但需要更多润色。您可以将其用作构建广义 select-paths 的指南。功能。

    您能否添加有关此问题如何出现或特定上下文的任何详细信息?这可能指向替代解决方案的想法。

    关于clojure - 如何按路径过滤 map 内容,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69047488/

    相关文章:

    Clojure:列表替换函数

    clojure - 设置位置(x、y、基本方向)并允许在 clojure 中更新

    dictionary - 在我的 Clojure 程序中将 map 更改为 pmap 会导致奇怪的异常 (ClassCastException)

    clojure 的 emacs slime-connect 版本不会查找 $CLASSPATH

    clojure - Clojure 中的 fn 和 defn 有什么区别?

    clojure - 有没有 clojure 工具可以查看 Clojure 如何使用 JVM 内存?

    jvm - 使用 Clojure/JVM 的守护进程

    vector - 为什么(=(vector nil)(vec nil))返回false?

    clojure - 您如何为 Leiningen 配置专有依赖项?

    clojure - 如何使用枚举/引用的实体 id 执行 Datomic 事务?