我正在学习clojure(来自ruby)并且在围绕生成集合的最佳方式时遇到一些麻烦。
我想编写一个带有两个参数的函数 - 向量ary
和整数sum
- 并生成一个新的2D向量,其中每一行的和是< =输入sum(忽略输入验证)。我遇到问题的概念是如何在建立新集合的同时保持“当前行总和”的状态。
这就是我所拥有的:
(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]]
我知道这里有一些混乱的东西,但我认为这个问题的惯用答案会很有启发性。
答案 0 :(得分: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]]
答案 1 :(得分:2)
正如Michał所示,累积状态a可以与元素中的元组连接。
以下是一种必要的方法,其中状态以循环绑定方式保存。
(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)))))
除此之外:争论顺序应该可以逆转。对序列元素起作用的函数往往将序列作为最后一个参数。