Clojure 在列表的每两个元素上映射一个函数
我需要一个只在其他元素上映射函数的函数,例如Clojure 在列表的每两个元素上映射一个函数,clojure,map-function,Clojure,Map Function,我需要一个只在其他元素上映射函数的函数,例如 (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 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)))))))
有没有更好的方法来实现这一点?在使用循环和重现之前,最好先看看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加上多个算术运算,以处理分区集合的最后一个元素为单例(输入长度为奇数)的情况。此外,由于要将该函数应用于集合中的某些特定标记项(在这种情况下为偶数索引),因此可以使用
映射索引,像这样:
(defn flipflop [f coll]
(map-indexed #(if (even? %1) (f %2) %2) coll))
鉴于此,您可以稍微简化循环
-重复
解决方案:
(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)))))))
这使用了两个常见技巧:
- 如果累积列表的顺序错误,请使用向量
相反
- 在可能的情况下,将公共元素分解为条件
比我的选择(为了比较和启发起见,我留下了这个选择)要好得多,确实非常简洁:),但你的选择也很有趣。
(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)))))))