如何按指定路径过滤深层嵌套map内容,保留目标字段?
Clojure 原生实现方案
以下实现无第三方依赖,完美适配嵌套列表场景、公共前缀路径筛选需求:
(defn select-paths [m paths] (letfn [(process [node path-prefix] (cond ;; 处理序列/列表节点,对每个元素复用当前路径规则筛选 (sequential? node) (mapv #(process % path-prefix) node) ;; 处理map节点,按路径前缀匹配筛选键 (map? node) (->> node (keep (fn [[k v]] (let [new-prefix (conj path-prefix k)] ;; 仅保留存在匹配路径前缀的键 (when (some #(= (take (count new-prefix) %) new-prefix) paths) (if (contains? (set paths) new-prefix) ;; 当前路径为完整指定路径,直接保留值 [k v] ;; 当前路径为前缀,递归处理下一级 [k (process v new-prefix)]))))) (into {})) ;; 基础类型节点直接返回 :else node))] (process m [])))
测试验证
用你提供的示例数据调用,返回结果和预期完全一致:
(def m {: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}}}
Java Jackson 实现方案
如果是Java生态处理JSON场景,可基于Jackson的JsonNode实现相同逻辑:
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.JsonNodeFactory; import com.fasterxml.jackson.databind.node.ObjectNode; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; public class PathSelector { public JsonNode selectPaths(JsonNode root, List<List<String>> paths) { return process(root, new ArrayList<>(), paths); } private JsonNode process(JsonNode node, List<String> currentPrefix, List<List<String>> paths) { // 处理数组节点 if (node.isArray()) { ArrayNode resultArr = JsonNodeFactory.instance.arrayNode(); for (JsonNode item : node) { resultArr.add(process(item, new ArrayList<>(currentPrefix), paths)); } return resultArr; } // 处理对象节点 if (node.isObject()) { ObjectNode resultObj = JsonNodeFactory.instance.objectNode(); Iterator<Map.Entry<String, JsonNode>> fields = node.fields(); while (fields.hasNext()) { Map.Entry<String, JsonNode> field = fields.next(); List<String> newPrefix = new ArrayList<>(currentPrefix); newPrefix.add(field.getKey()); // 检查是否有路径匹配当前前缀 boolean hasMatch = paths.stream() .anyMatch(path -> path.size() >= newPrefix.size() && path.subList(0, newPrefix.size()).equals(newPrefix)); if (hasMatch) { if (paths.contains(newPrefix)) { resultObj.set(field.getKey(), field.getValue()); } else { resultObj.set(field.getKey(), process(field.getValue(), newPrefix, paths)); } } } return resultObj; } // 基础类型直接返回 return node; } }
内容的提问来源于stack exchange,提问作者siltalau
相关产品推荐
相关产品推荐

