3

与えられた 2 つのシーケンスをインターリーブする関数を書きたいと思います。関数は次のように動作する必要があります。

user=> (ext-interl '(1 2 3 4 5 6 7 8) '(a b c))
(1 a 2 b 3 c 4 a 5 b 6 c 7 a 8 b)

より長いシーケンスに達すると、プロセスは終了します。

私のコードは次のとおりです。

(defn ext-interl [l1 l2]
 (lazy-seq
  (let [ls1 (seq l1) ls2 (seq l2)]
    (cond (and ls1 ls2)
     (cons (first ls1) (cons (first ls2) (ext-interl (rest ls1) (rest ls2))))
     ls1 ls1
     ls2 ls2))))

しかし、このコードは次のように実行されます。

 user=> (ext-interl '(1 2 3 4 5 6 7 8) '(a b c))
(1 a 2 b 3 c 4 5 6 7 8)

このコードを修正するにはどうすればよいですか? ありがとうございました!

4

2 に答える 2

3

ソリューションは 2 番目と 3 番目condの句で失敗します。シーケンスの 1 つが完全に使用されている場合は、残りの 1 つを最後に追加するだけです。おそらく、残りのコレクションを最初から他の 1 サイクルとマージする別の関数を呼び出す必要があります。例えば:

(defn- ext-interleave' [orig-xs xs orig-ys ys]
  (let [xs (seq xs)
        ys (seq ys)]
    (cond
      (and xs ys)
      (concat
        [(first xs) (first ys)]
        (ext-interleave' orig-xs (rest xs) orig-ys (rest ys)))

      xs
      (interleave xs (cycle orig-ys))

      ys
      (interleave (cycle orig-xs) ys))))

(defn ext-interleave [xs ys]
  (ext-interleave' xs xs ys ys))

(ext-interleave [1 2 3 4 5 6 7 8] '[a b c])

condこの解決策は、最初のブランチでほとんど怠惰です (両方のシーケンスから最初の 2 つのアイテムを熱心に消費します) 。

怠惰なソリューションが必要ない場合は、既存の関数を使用してこれを機能させます。

  • cycle+takeシーケンスを必要なだけ長くする
  • interleaveそれらを組み合わせるコア

解決:

(defn ext-interleave [xs ys]
  (let [l (max (count xs) (count ys))
        xs (take l (cycle xs))
        ys (take l (cycle ys))]
    (interleave xs ys)))
(ext-interleave [1 2 3 4 5 6 7 8] '[a b c])
;; => (1 a 2 b 3 c 4 a 5 b 6 c 7 a 8 b)

任意の数の入力シーケンスに対して機能させることもできます。

(defn ext-interleave' [& cols]
  (let [l (apply max (map count cols))
        cols (map #(take l (cycle %)) cols)]
    (apply interleave cols)))

(ext-interleave' [1 2 3 4 5 6 7 8] '[a b c] [:y :z])
;; => (1 a :y 2 b :z 3 c :y 4 a :z 5 b :y 6 c :z 7 a :y 8 b :z)

count提供されたソリューションは、要素をカウントするために入力シーケンスを強制的に実現するため、怠惰ではありません。

于 2016-05-02T20:03:36.020 に答える