4

私は clojure (ruby から来ている) を学んでいて、コレクションを生成する最良の方法に頭を悩ませています。

aryベクトルと整数の 2 つの引数を取りsum、各行の合計が入力の合計より小さい (入力検証を無視する) 新しい 2D ベクトルを生成する関数を書きたいと思います。私が問題を抱えている概念的なポイントは、「現在の行の合計」の状態を維持しながら、新しいコレクションを構築する方法です。

これが私が持っているものです:

(defn split-after-sum [ary sum]
  (reduce (fn [acc i]
            (let [inner-sum (+ (last acc) i)]
              (if (< inner-sum sum)
                [(conj (first acc) i) (+ i (last acc))]
                [(conj (first acc) i "X") 0])))
          [[] 0] ary))

reduce作成中のコレクションとこの行の合計数の両方を追跡するために、2 要素のベクトルを渡しています。

それは一種の作品です。結果を実際に 2D 配列にする方法がわからないので、分割する必要がある場所に「X」を貼り付けるだけです。

(first (split-after-sum [1 1 1 1 1 1 1 1 1] 2)) => [1 1 "X" 1 1 "X" 1 1 "X" 1 1 "X" 1]

理想的な出力は次のようになります。

(split-after-sum [1 1 1 1 1 1 1 1 1] 2) => [[1 1] [1 1] [1 1] [1 1] [1]]

ここでいくつかのことがごちゃ混ぜになっていることは知っていますが、この問題に対する慣用的な答えは啓発的だと思います。

4

2 に答える 2

7
(defn split-after-sum [ary sum]
  (let [[acc v] (reduce (fn [[acc v s] x]
                          (let [new-s (+ s x)]
                            (if (<= new-s sum)
                              [acc (conj v x) new-s]
                              [(conj acc v) [x] x])))
                        [[] [] 0]
                        ary)]
    (conj acc v)))

(split-after-sum [1 1 3 2 1 1 1 1 1] 3)
;= [[1 1] [3] [2 1] [1 1 1] [1]]
(split-after-sum [1 1 3 2 1 1 1 1 1] 4)
;= [[1 1] [3] [2 1 1] [1 1 1]]
(split-after-sum [1 1 3 2 1 1 1 1 1] 5)
;= [[1 1 3] [2 1 1 1] [1 1]]
(split-after-sum [1 1 3 2 1 1 1 1 1] 6)
;= [[1 1 3] [2 1 1 1 1] [1]]
于 2013-08-03T21:18:36.777 に答える