2010-12-16 3 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の代わりに、欠損値を生成するために2番目の関数を渡す方が良いでしょう(例:#(identity "--"))。

使用例:私は、Clojure/Functional Programmingを学ぶ練習として、小さなテキストスパイダーソリティアプレーヤーを作成しています。私はゲーム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)))))))) 

テスト:私はむしろmissing-value-seqものよりmissing-value-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 

注意。

アップデートはコメントで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 Sに置き換えられますのでご注意ください。

(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で簡単に追加することができます:あなたがポイントを得ることができるように、バージョンを

+0

'(?ではない、すべてのゼロ初)' - それは[「C3 nil 'のC1 C2']のようなシーケンスのために動作しません。 – ffriend

+0

@ffriend:テストコードを教えてもらえますか? –

+1

これらの配列を試してください:['a1' a2 nil] ['b1' b2] ['c1' c2 nil 'c4]。 'firsts'を計算する前に'(every?empty?cols) 'をチェックし、' firsts'の計算を '(map first-or-val(conj colls c1))'(私の答えを参照)で置き換えることによって、修正できます。 – ffriend

1

これは完全にあなたが必要とする機能ではありませんが、少しの簡素化を図ります。私もmissing-value-seqmissing-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