Clojure “有没有更好、更惯用的方法?”;“虽然还不够”;从一个seq?

Clojure “有没有更好、更惯用的方法?”;“虽然还不够”;从一个seq?,clojure,Clojure,我需要根据一些数量规则从序列中提取一些元素。我想出了一个解决方案: (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

我需要根据一些数量规则从序列中提取一些元素。我想出了一个解决方案:

(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数据);1.累积值的顺序
(地图矢量数据);2.与原始序列配对
(取while#(<(第二个%));3.直到某个累积值
(地图优先);4.然后提取原始值

我的第一个想法是将此问题视为reduce的一个变体,从而将问题分为两个步骤:

  • 计算结果中的项目数
  • 从输入中提取那么多
我对参数名称也有一些自由:

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)  
user>(在没有足够的[reducer fn limit data]时执行defn)
(取(dec(计数(取时#)(<%限值)(减少值fn 0数据)))
(数据)
#'用户/获取时间不够
用户>(在不足的情况下采取行动35;(+%1(%2 1))7[[2 5][7 8][2 1]]
([2 5])     
用户>(不足时采取+10[2 5 7 8 2 1])
(2 5)  

这将返回一个序列,您的示例将返回一个向量,如果这很重要,那么您可以添加对
vec
的调用。如果您想使用flatland/Usage,这是一种不错的使用方法:

但每次它决定是否增加块时,它都会为整个“已处理到目前为止”块重建累加器,因此它是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))

只会遍历输入序列一次的内容:

(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)))
(在没有足够[r v数据]
(>>(其余(减少(fn[s i][(r(s 0)i)i])[0[]]数据))
(先休息一会儿(比较(<%v))
(图二)

有时
懒惰的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 limit coll](在f limit(f)coll不足时进行)
([f限制acc coll]
(续)
(当let[s(seq coll)]
(让[fst(第一个)
nacc(f acc fst)]
(当(
注:
f
应遵循reduce规则

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