如何附加到clojure vec,直到与累计vec相关的特定条件为真?
对于我的最小示例,我希望将映射附加到vec中,直到其中一个映射字段的总和达到某个限制 这是我的尝试。显然是错误的,因为如何附加到clojure vec,直到与累计vec相关的特定条件为真?,clojure,Clojure,对于我的最小示例,我希望将映射附加到vec中,直到其中一个映射字段的总和达到某个限制 这是我的尝试。显然是错误的,因为项在while循环中不会更改 (let [items []] (into items (while (< (reduce + (map :count items)) 100) {:something "x" :count (+ 1 (rand-int 25))}))) (让[项目[]] (进入项目(
项在while循环中不会更改
(let [items []]
(into items (while (< (reduce + (map :count items)) 100)
{:something "x"
:count (+ 1 (rand-int 25))})))
(让[项目[]]
(进入项目(同时(<(减少+(映射:计数项目))100)
{:某个“x”字
:计数(+1(rand int 25))})
您可以使用减少来实现这一点,同时保持:计数的运行总和:
(defn random-map []
{:something "x"
:count (inc (rand-int 25))})
(reduce
(fn [[out sum] {:keys [count] :as m}]
(let [new-sum (+ sum count)]
(if (< new-sum 100)
[(conj out m) (+ sum count)]
(reduced out))))
[[] 0] ;; initial accumulator: empty output and sum is 0
(repeatedly random-map))
=>
[{:something "x", :count 7}
{:something "x", :count 4}
{:something "x", :count 14}
{:something "x", :count 10}
{:something "x", :count 22}
{:something "x", :count 4}
{:something "x", :count 20}
{:something "x", :count 17}]
(apply + (map :count *1))
=> 98
另一种可能更容易理解/使用的措辞:
(as-> (repeatedly random-map) maps
(map #(assoc %1 :running-sum %2) maps (reductions + (map :count maps)))
(take-while #(< (:running-sum %) 100) maps))
(as->(重复随机映射)映射
(映射#(关联%1:运行总和%2)映射(减少+(映射:计数映射)))
(取而代之#(<(:运行总和%)100)地图)
reductions
版本更简洁,但需要更多的多元性map
知识,在某些情况下可能效率较低。对于一个运行总数,reductions
是一个很好的答案
如果你有一个更一般的谓词要考虑,请看:
(s/defn取结果
“从基于带集合参数的谓词的集合中获取。
继续从源集合获取数据,直到`(pred)`为false。
如果pred从不为假,则返回'coll'
[pred:-s/Any;采用列表参数的谓词函数
coll:-tsk/列表]
(何时(空?coll)
(throw(ex info)项不能为空“{:coll coll}”)
(让[所有VAL(vec coll)
数值VAL(计算所有VAL)]
(循环[i]1
结果[];从获取第一个值开始
(如果(
以及单元测试:
(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}])))
(dotest
(让[项目[{:名称:a:计数1}
{:name:b:count 2}
{:name:c:count 3}
{:name:d:count 4}
{:name:e:count 5}]
总和计数(fn总和计数fn[项目](减少+(映射:计数项目)))]
(抛出?(t/在结果时进行)#(
(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}])))