我需要根据一些数量规则从序列中获取一些元素。这是我提出的解决方案:
(defn take-while-not-enough
[p len xs]
(loop [ac 0
r []
s xs]
(if (empty? s)
r
(let [new-ac (p ac (first s))]
(if (>= new-ac len)
r
(recur new-ac (conj r (first s)) (rest s)))))))
(take-while-not-enough + 10 [2 5 7 8 2 1]) ; [2 5]
(take-while-not-enough #(+ %1 (%2 1)) 7 [[2 5] [7 8] [2 1]]) ; [[2 5]]
有没有更好的方法来实现同样的目标?
感谢。
更新
有人发布了该解决方案,但之后将其删除了。它同样是我接受的答案,但更具可读性。谢谢你,匿名的祝福者!
(defn take-while-not-enough [reducer-fn limit data]
(->> (reductions reducer-fn 0 data) ; 1. the sequence of accumulated values
(map vector data) ; 2. paired with the original sequence
(take-while #(< (second %) limit)) ; 3. until a certain accumulated value
(map first))) ; 4. then extract the original values
答案 0 :(得分:2)
我的第一个想法是将此问题视为减少的变体,从而将问题分解为两个步骤:
我还对参数名称采取了一些自由:
user> (defn take-while-not-enough [reducer-fn limit data]
(take (dec (count (take-while #(< % limit) (reductions reducer-fn 0 data))))
data))
#'user/take-while-not-enough
user> (take-while-not-enough #(+ %1 (%2 1)) 7 [[2 5] [7 8] [2 1]])
([2 5])
user> (take-while-not-enough + 10 [2 5 7 8 2 1])
(2 5)
这将返回一个序列,您的示例会返回一个向量,如果这很重要,那么您可以添加对vec
的调用
答案 1 :(得分:1)
只能遍历输入序列一次的东西:
(defn take-while-not-enough [r v data]
(->> (rest (reductions (fn [s i] [(r (s 0) i) i]) [0 []] data))
(take-while (comp #(< % v) first))
(map second)))
答案 2 :(得分:0)
好吧,如果你想使用平地/有用,这是一种使用glue
的好方法:
(defn take-while-not-enough [p len xs]
(first (glue conj []
(constantly true)
#(>= (reduce p 0 %) len)
xs)))
但是每当它决定是否增加块数时,它就会为整个“处理过的”块重建累加器,所以它是O(n ^ 2),这对于更大的输入来说是不可接受的。
对您的实现最明显的改进是使其变得懒惰而不是尾递归:
(defn take-while-not-enough [p len xs]
((fn step [acc coll]
(lazy-seq
(when-let [xs (seq coll)]
(let [x (first xs)
acc (p acc x)]
(when-not (>= acc len)
(cons x (step acc xs)))))))
0 xs))
答案 3 :(得分:0)
有时lazy-seq
是直截了当且自我解释的。
(defn take-while-not-enough
([f limit coll] (take-while-not-enough f limit (f) coll))
([f limit acc coll]
(lazy-seq
(when-let [s (seq coll)]
(let [fst (first s)
nacc (f acc fst)]
(when (< nxt-sd limit)
(cons fst (take-while-not-enough f limit nacc (rest s)))))))))
注意:f
应遵循reduce规则。