Clojure-在最内层过滤嵌套地图

时间:2019-01-11 09:32:26

标签: dictionary filter clojure

什么是过滤以下嵌套地图,保持嵌套地图结构的最佳方法。在我的示例中,爱丽丝和鲍勃可以重复,例如同一位员工一次可以在多个不同的工厂工作。

.c

例如,我想按年龄> 30进行过滤并返回相同的地图结构。理想情况下,此方法适用于任何嵌套地图深度,并在最内层进行过滤。预期结果:

.c

我看过clojure filter nested map to return keys based on inner map values,但看起来并不能解决我的问题。谢谢

3 个答案:

答案 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))]))))))