迭代嵌套映射的所有键

时间:2015-09-29 20:16:39

标签: clojure

假设:

{:o {:i1 1
     :i2 {:ii1 4}}}

我想在"绝对"中迭代地图的键。从根形成一个向量。所以我想:

{
 [:o :i1] 1
 [:o :i2 :ii1] 4
}

结果。基本上只获取叶节点。

2 个答案:

答案 0 :(得分:3)

我认为使用for代替mapcat的版本更为出色:

(defn flatten-keys [m]
  (if (not (map? m))
    {[] m}
    (into {}
          (for [[k v] m
                [ks v'] (flatten-keys v)]
            [(cons k ks) v']))))

该函数自然是递归的,非映射的最方便的基本情况是“这一个值,没有keyseq导致它”。对于地图,您只需在地图中的每个值上调用flatten-keys,并将其键前置于结果地图的每个keyseq。

答案 1 :(得分:2)

看起来这基本上是嵌套键的扁平化。这似乎也是a 4clojure problem

flatten-map search on github会产生很多结果。

一个示例实现:

using System;
using System.Text.RegularExpressions;

class Program
{
    static void Main()
    {
        string pattern = @"(?x)^(\w+-\w+-\w+-\w+)$";
        Regex reg = new Regex(pattern);
        string test = "word-6798-3401-001";

        if((reg.Match(test).Success))
            foreach (var x in test.Split(new char[] {'-'}))
                Console.WriteLine(x);
    }
}

实施例

(defn flatten-map 
  "Flattens the keys of a nested into a map of depth one but 
   with the keys turned into vectors (the paths into the original 
   nested map)."
  [s]
  (let [combine-map (fn [k s] (for [[x y] s] {[k x] y}))]
    (loop [result {}, coll s]
      (if (empty? coll)
        result
        (let [[i j] (first coll)]
          (recur (into result (combine-map i j)) (rest coll)))))))

来自Christoph Grand的更为通用的版本:

(flatten-map {:OUT
              {:x 5
               :x/A 21
               :x/B 33
               :y/A 24}})
=> {[:OUT :x] 5, [:OUT :x/A] 21, [:OUT :x/B] 33, [:OUT :y/A] 24}

示例:

(defn flatten-map
  "Take a nested map (or a nested collection of key-value pairs) and returns a
   sequence of key-value pairs where keys are replaced by the result of calling
   (reduce f pk path) where path is the path to this key through the nested
   maps."
  ([f kvs] (flatten-map f nil kvs))
  ([f pk kvs]
   (mapcat (fn [[k v]]
             (if (map? v)
               (flatten-map f (f pk k) v)
               [[(f pk k) v]])) kvs)))