2016-03-19 152 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))))))) 

它使用幾個常見的招數:

  • 如果累積列表順序錯誤出來,使用矢量 代替。
  • 在可能的情況下,將條件中的常見元素分解出來。
相關問題