我需要一个只在每个其他元素上映射函数的函数,例如
(f inc '(1 2 3 4))
=> '(2 2 4 4)
我想出了:
(defn flipflop [f l]
(loop [k l, b true, r '()]
(if (empty? k)
(reverse r)
(recur (rest k)
(not b)
(conj r (if b
(f (first k))
(first k)))))))
有没有更好的方法来实现这个目标?
答案 0 :(得分:15)
(map #(% %2)
(cycle [f identity])
coll)
答案 1 :(得分:1)
在使用循环和重复之前查看Clojure的更高级函数是个好主意。
user=> (defn flipflop
[f coll]
(mapcat #(apply (fn ([a b] [(f a) b])
([a] [(f a)]))
%)
(partition-all 2 coll)))
#'user/flipflop
user=> (flipflop inc [1 2 3 4])
(2 2 4 4)
user=> (flipflop inc [1 2 3 4 5])
(2 2 4 4 6)
user=> (take 11 (flipflop inc (range))) ; demonstrating laziness
(1 1 3 3 5 5 7 7 9 9 11)
这个触发器不需要反转输出,它是懒惰的,我觉得它更容易阅读。
该函数使用partition-all
将列表拆分为两个对的对,并使用mapcat将一系列两个元素序列从调用连接回一个序列。
该函数使用apply,加上多个arities,以处理分区集合的最后一个元素是单例的情况(输入的长度是奇数)。
答案 2 :(得分:1)
另外,既然您想将函数应用于集合中的某些特定指示项(在这种情况下甚至是索引),您可以使用map-indexed
,如下所示:
(defn flipflop [f coll]
(map-indexed #(if (even? %1) (f %2) %2) coll))
答案 3 :(得分:1)
虽然amalloy's solution ,但您可以稍微简化loop
- recur
解决方案:
(defn flipflop [f l]
(loop [k l, b true, r []]
(if (empty? k)
r
(recur (rest k)
(not b)
(conj r ((if b f identity) (first k)))))))
这使用了几个常见的技巧: