Для промежуточного итога, reductions
- хороший ответ.
Если у вас есть более общий предикат для рассмотрения, пожалуйста, посмотрите на функцию take-while-result
в библиотека Tupelo :
(s/defn take-while-result
"Takes from a collection based on a predicate with a collection argument.
Continues taking from the source collection until `(pred <taken-items>)` is falsey.
If pred is never falsey, `coll` is returned."
[pred :- s/Any ; a predicate function taking a list arg
coll :- tsk/List]
(when (empty? coll)
(throw (ex-info "items must not be empty" {:coll coll})))
(let [all-vals (vec coll)
num-vals (count all-vals)]
(loop [i 1
result []] ; start by taking first value
(if (< num-vals i)
result
(let [test-vals (subvec all-vals 0 i)]
(if (not (pred test-vals))
result
(recur (inc i) test-vals)))))))
и модульные тесты:
(dotest
(let [items [{:name :a :count 1}
{:name :b :count 2}
{:name :c :count 3}
{:name :d :count 4}
{:name :e :count 5}]
sum-count (fn sum-count-fn [items] (reduce + (map :count items)))]
(throws? (t/take-while-result #(<= (sum-count %) 0) []))
(is= (t/take-while-result #(<= (sum-count %) -1) items) [])
(is= (t/take-while-result #(<= (sum-count %) 0) items) [])
(is= (t/take-while-result #(<= (sum-count %) 1) items)
[{:name :a, :count 1}])
(is= (t/take-while-result #(<= (sum-count %) 2) items)
[{:name :a, :count 1}])
(is= (t/take-while-result #(<= (sum-count %) 3) items)
[{:name :a, :count 1} {:name :b, :count 2}])
(is= (t/take-while-result #(<= (sum-count %) 4) items)
[{:name :a, :count 1} {:name :b, :count 2}])
(is= (t/take-while-result #(<= (sum-count %) 5) items)
[{:name :a, :count 1} {:name :b, :count 2}])
(is= (t/take-while-result #(<= (sum-count %) 6) items)
[{:name :a, :count 1} {:name :b, :count 2} {:name :c, :count 3}])
(is= (t/take-while-result #(<= (sum-count %) 7) items)
[{:name :a, :count 1} {:name :b, :count 2} {:name :c, :count 3}])
(is= (t/take-while-result #(<= (sum-count %) 8) items)
[{:name :a, :count 1} {:name :b, :count 2} {:name :c, :count 3}])
(is= (t/take-while-result #(<= (sum-count %) 9) items)
[{:name :a, :count 1} {:name :b, :count 2} {:name :c, :count 3}])
(is= (t/take-while-result #(<= (sum-count %) 10) items)
[{:name :a, :count 1} {:name :b, :count 2} {:name :c, :count 3} {:name :d, :count 4}])
(is= (t/take-while-result #(<= (sum-count %) 11) items)
[{:name :a, :count 1} {:name :b, :count 2} {:name :c, :count 3} {:name :d, :count 4}])
(is= (t/take-while-result #(<= (sum-count %) 14) items)
[{:name :a, :count 1} {:name :b, :count 2} {:name :c, :count 3} {:name :d, :count 4}])
(is= (t/take-while-result #(<= (sum-count %) 15) items)
[{:name :a, :count 1} {:name :b, :count 2} {:name :c, :count 3} {:name :d, :count 4} {:name :e, :count 5}])
(is= (t/take-while-result #(<= (sum-count %) 16) items)
[{:name :a, :count 1} {:name :b, :count 2} {:name :c, :count 3} {:name :d, :count 4} {:name :e, :count 5}])))
Вам также могут быть интересны связанные функции:
(index-using pred coll)
(split-using pred coll)
(partition-using pred values)
(split-match coll tgt)