什么是过滤以下嵌套地图,保持嵌套地图结构的最佳方法。在我的示例中,爱丽丝和鲍勃可以重复,例如同一位员工一次可以在多个不同的工厂工作。
.c
例如,我想按年龄> 30进行过滤并返回相同的地图结构。理想情况下,此方法适用于任何嵌套地图深度,并在最内层进行过滤。预期结果:
.c
我看过clojure filter nested map to return keys based on inner map values,但看起来并不能解决我的问题。谢谢
答案 0 :(得分:2)
这与先前的问题之一非常相似:
(use '[com.rpl.specter])
(let [input {:customer1
{:plant1
{"Alice" {:age 35 :sex "F"}
"Bob" {:age 25 :sex "M"}}
:plant2 {}}
:customer2 {}}
desired-output {:customer1
{:plant1 {"Alice" {:age 35 :sex "F"}}
:plant2 {}}
:customer2 {}}
RECUR-MAP (recursive-path [] p (cond-path map? (continue-then-stay [MAP-VALS p])))]
(clojure.test/is (= (setval [RECUR-MAP (pred :age) #(> 30 (:age %))] NONE input)
desired-output)))
答案 1 :(得分:1)
您的数据有点不寻常,因为通常会期望:customer1
,:customer2
等是向量中的不同条目。对于这样的半结构化数据,我会考虑使用postwalk
:
(ns tst.demo.core
(:use tupelo.core demo.core tupelo.test)
(:require
[clojure.walk :as walk] ))
(def universe
{:customer1
{:plant1
{"Alice" {:age 35 :sex "F"}
"Bob" {:age 25 :sex "M"}}
:plant2 {}}
:customer2 {}})
(def age-of-wisdom 30)
(defn wisdom-only
[form]
(let [filter-entry? (when (map-entry? form)
(let [[-name- details] form
age (:age details)] ; => nil if missing
(and age ; ensure not nil
(< age age-of-wisdom))))]
(if filter-entry?
{}
form)))
(walk/postwalk wisdom-only universe) =>
{:customer1
{:plant1
{"Alice" {:age 35, :sex "F"}}
:plant2 {}}
:customer2 {}}
答案 2 :(得分:0)
感谢@akond的回答,阅读代码使我想到了一种非幽灵的解决方案。仍然令我有些惊讶的是,在此用例中没有简单的方法来应用filter
。
(defn recursive-filter [pred k m]
(letfn [(pair-filter [pair] (if (pred (k (second pair))) pair nil))]
(into {}
(for [a m]
(if (empty? (second a))
[(first a) {}]
(if (contains? (second a) k)
(pair-filter a)
[(first a) (recursive-filter pred k (second a))]))))))