将包含不同区域的列表转换为Map

时间:2015-04-09 04:07:29

标签: clojure idiomatic

转换此表单的列表:

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

进入此地图:

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

我可以看到非常丑陋的方式来做到这一点。但Clojure的做法是什么?

  .
  .
  .

(P.S。我对Clojure的早期反应是它感觉有点像       优化了更多"玩具般的"任务。如果逻辑连接您的输入       和输出有任何头发,然后我觉得我花了更多       努力打击语言而不是问题。特别,       跟踪你的复发中的第五个参数'声明感觉       就像我正在做一些编译器应该做的事情......       但也许我的Clojure愿景仍然太弱......)

2 个答案:

答案 0 :(得分:4)

这是一个解决方案:

(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)将两个序列“拉”成一张地图,使用range中与vals一样多的整数。

答案 1 :(得分:1)

(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进行一些预处理,但在这种情况下循环可能最干净。