Reduce stateful clojure collections

I study clojure (coming from ruby) and experiencing some problems, enveloping my head in the best way to create collections.

I would like to write a function that takes two arguments - the ary vector and the integer sum - and generates a new 2D vector in which each row sum is equal to <= input sum (ignore the input Check). The conceptual point with which I am having problems is to save the state of "sum of the current line", as well as create a new collection.

Here is what I have:

 (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)) 

I pass reduce 2-element vector to track both the collection I am collecting and the total number of this row.

This is kind of work. I did not understand how to actually make the result a 2D array, so it just sticks to "X" where the splits should be:

 (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] 

Ideal yield:

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

I know that there are several things, but I think that the idiomatic answer to this problem will be enlightened.

+4
source share
2 answers
 (defn split-after-sum [ary sum] (let [[acc v] (reduce (fn [[acc vs] x] (let [new-s (+ sx)] (if (<= new-s sum) [acc (conj vx) 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]] 
+7
source

As Michaล‚ shows, the cumulative state of a can be combined into a tuple with an associated element.

The following is an imperative approach in which the state is held in a loop binding.

 (defn split-after-sum [ary sum] (when (seq ary) (loop [ary ary cur 0 row [] rows []] (if-let [[x & xs] ary] (let [nxt (+ x cur)] (if (<= nxt sum) (recur xs nxt (conj row x) rows) (recur xs x [x] (conj rows row)))) (conj rows row))))) 

In addition, the order of the arguments should probably be reversed. Functions that work on sequence elements tend to perceive a sequence as the last argument.

+2
source

Source: https://habr.com/ru/post/1495140/


All Articles