2010-12-16 14 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