将具有不同区域的列表转换为地图

Convert a list with to distinct regions into a Map

转换此形式的列表:

 ( arg1  arg2 ... :first_keyword val_1 :key2 val_2 ... )

进入这张地图:

 { 1 arg1, 2 arg2, ..., :first_keyword val_1, :key2 val_2, ... }

我可以看到执行此操作的非常丑陋的方法。但是 Clojure 的方法是什么?

  .
  .
  .

(P.S。我对 Clojure 的早期反应是感觉有点像 针对更多 "toy-like" 任务进行了优化。如果逻辑连接你的输入 并且输出有任何毛发,然后我觉得我花了更多 努力与语言而不是问题作斗争。具体来说, 跟踪 'recurs' 语句中的第五个参数感觉 就像我正在做编译器应该做的事情...... 不过可能我的Clojure眼光还是太弱了...)

(loop [inputs ["arg1" "arg2" :key1 1 :key2 2] index 1 output {}]
  (if (empty? inputs) output
    (let [input (first inputs) rest-inputs (rest inputs)]
      (if (keyword? input)
        (recur (rest rest-inputs) index (assoc output input (second inputs)))
        (recur rest-inputs (inc index) (assoc output index input))))))

您可以使用 for 理解或 reduce 进行一些预处理,但在这种情况下循环可能是最干净的。

这是一种解决方案:

(let [[vals keyvals]
      (split-with (complement keyword?) 
                  [100 101 102 :a 103 :b 104 :c 105])]
  (merge (zipmap (range) vals) 
         (apply hash-map keyvals)))

=> {:a 103, :b 104, :c 105, 2 102, 1 101, 0 100}

这使得 0 成为第一个元素的键。如果你想要基于 1 的键,你可以将 (range) 包装在 (map inc _).

其他说明:

(split-with (complement keyword?) ...) 将序列分成两部分:一个没有关键字的序列,其余部分。

(zipmap (range) vals) "zips" 两个序列一起组成一个映射,使用 range 中的整数与 vals.

中的整数一样多