2010-12-16 10 views
5

我正在嘗試編寫一個名爲map-longest的Clojure實用程序函數(讚賞備用名稱建議)。該功能將有以下的「簽名」:Clojure map-longest

(map-longest fun missing-value-seq c1 & colls) 

,將類似的行爲map,除了比將繼續處理集合品,直到最長耗盡。對於收集時間最短的數據,當數據用完時,它將從missing-values-seq中獲取它們。它應該是懶惰的,但顯然不能用於無限集合。

使用例:

(print (apply str 
    (map-longest #(str %1 \space %2 \space %3 \newline) (repeatedly "--") 
    ["a1" "a2" "a3"] ["b1" "b2"] ["c1" "c2" "c3" "c4"]))) 

應該產生下面的輸出:

a1 b1 c1 
a2 b2 c2 
a3 -- c3 
-- -- c4 

但我可能有錯誤的呼叫。

我該如何實施? clojure.core或clojure-contrib庫是否已經有這樣的東西?作爲missing-value-seq的替代方案,是否最好傳遞第二個函數來生成缺失值(例如:在我的示例中爲#(identity "--"))?

使用案例:我正在寫一個小型的文本蜘蛛紙牌播放器作爲學習Clojure /函數式編程的練習。我需要能夠顯示遊戲tableaus(純粹主義者的tableaux :-))。

回答

4

這裏是一個解決方案:

(defn map-longest 
    ([fn missing-value-fn c1] 
    (map fn c1)) 
    ([fn missing-value-fn c1 & colls] 
    (lazy-seq 
     (when (not-every? empty? (conj colls c1)) 
     (let [firsts (map first (conj colls c1))] 
      (cons 
      (apply fn (map #(if (nil? %) (missing-value-fn) %) firsts)) 
      (apply map-longest 
       (conj (map rest colls) (rest c1) missing-value-fn fn)))))))) 

測試:

user=> (print (apply str 
     (map-longest #(str %1 \space %2 \space %3 \newline) #(identity "--") 
      ["a1" "a2" "a3"] ["b1" "b2"] ["c1" "c2" "c3" "c4"]))) 
a1 b1 c1 
a2 b2 c2 
a3 -- c3 
-- -- c4 
nil 

請注意,我已經採取了missing-value-fn方法,而不是missing-value-seq之一。

更新

更新的代碼,以通過ffriend在評論中提到了這樣的情況。

測試:

user=> (print (apply str 
      (map-longest #(str %1 \space %2 \space %3 \newline) #(identity "--") 
      ["a1" "a2" nil] ["b1" "b2"] ["c1" "c2" nil "c4"]))) 
a1 b1 c1 
a2 b2 c2 
-- -- -- 
-- -- c4 
nil 

請注意,這將與由missing-value-fn返回的值colls更換nil秒。

+0

'(未每零首創?)' - 它不會像[ 'C1' C2零「C3〕序列工作。 – ffriend 2010-12-16 14:41:56

+0

@朋友:你能給一個測試代碼嗎? – 2010-12-16 14:43:11

+1

試試這些序列:['a1'a2 nil] ['b1'b2] ['c1'c2 nil'c4]。你可以在計算'firsts'並用'(map first-or-val(conj colls c1))'替換計算'firsts'本身之前檢查'(every?empty?cols)'來修復它(見我的答案)。 – ffriend 2010-12-16 15:21:14

1

這不是完全的功能,你需要的,但更簡單的版本,所以你可以明白了吧:

(defn first-or-val [col missing] 
    (if (empty? col) 
    missing 
    (first col))) 

(defn map-longest [f missing-value & cols] 
    (loop [cols cols, ret '()] 
    (cond (every? empty? cols) (reverse ret) 
      :else (recur (map rest cols) 
         (conj ret (apply f (map #(first-or-val % missing-value) 
               cols))))))) 

我省略了懶惰,你可以用delayforce輕鬆地添加它。我也將missing-value-seq更改爲missing-value - 我相信這不是您用序列或發生器替換它的問題。

實施例:

(print (apply str 
      (map-longest #(str %1 \space %2 \space %3 \newline) "--" 
         ['a1 'a2 'a3] ['b1 'b2] ['c1 'c2 'c3 'c4]))) 

結果:

a1 b1 c1 
a2 b2 c2 
a3 -- c3 
-- -- c4