2016-03-19 106 views
2

我需要一个函数,该函数仅在每个其他元素上映射一个函数,例如,在列表的每两个元素上映射一个函数

(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))))))) 

有一个漂亮的方式来实现这一目标?

回答

14
(map #(% %2) 
    (cycle [f identity]) 
    coll) 
+0

比我的选择要好得多(我为了比较和启发的目的而留下的) – noisesmith

+0

确实非常整齐:),但您的选择也很有趣。 – tumasgiu

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来处理分区集合的最后一个元素是单例(输入长度​​奇数)的情况。

1

还,因为你要的功能应用到集合中的一些具体indiced项目(即使在这种情况下,索引)你可以使用map-indexed,像这样:

(defn flipflop [f coll] 
    (map-indexed #(if (even? %1) (f %2) %2) coll)) 
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))))))) 

它使用几个常见的招数:

  • 如果累积列表顺序错误出来,使用矢量 代替。
  • 在可能的情况下,将条件中的常见元素分解出来。
相关问题