Loops 将值添加到匹配谓词的第一个(列表的)列表

Loops 将值添加到匹配谓词的第一个(列表的)列表,loops,clojure,immutability,Loops,Clojure,Immutability,我有一个列表和一个值。我的目标是创建一个新的列表列表,其中值(新的第一项)与匹配谓词的第一个列表(例如>与列表的第一项)相关联。如果没有与谓词匹配的列表,我希望我的值在列表的末尾“开始”一个新列表 if my list is: ['(2 3 4) '(4 5 6 7) '(5 6 7)] and my value: 3 and my predicate: (comp (partial < my-value) first) then my result should be: ['(2 3 4

我有一个列表和一个值。我的目标是创建一个新的列表列表,其中值(新的第一项)与匹配谓词的第一个列表(例如>与列表的第一项)相关联。如果没有与谓词匹配的列表,我希望我的值在列表的末尾“开始”一个新列表

if my list is: ['(2 3 4) '(4 5 6 7) '(5 6 7)]
and my value: 3
and my predicate: (comp (partial < my-value) first)
then my result should be: ['(2 3 4) '(3 4 5 6 7) '(5 6 7)]

if my value was: 10
my result should be: ['(2 3 4) '(4 5 6 7) '(5 6 7) '(10)]
(它崩溃了) 请用一些clojure的表情来启发我:)

顺便说一句,我想作为最长递增子序列问题的一部分来解决这个问题。

这使用循环重现

(defn add-to-ll
  [ll pred value]
  (loop [[current & unprocessed] ll
         processed []]
    (cond
     (pred current) (concat processed
                            [(cons value current)]
                            unprocessed)
     (empty? unprocessed) (concat processed
                                  [current]
                                  [[value]])
     :else (recur unprocessed
                  (conj processed current)))))


 (def l-l1 [[2 3 4] [4 5 6 7] [5 6 7]])
 (add-to-ll l-l1 (comp (partial < 10) first) 10)
 => ([2 3 4] [4 5 6 7] [5 6 7] [10])

 (add-to-ll l-l1 (comp (partial < 3) first) 3)
 => ([2 3 4] (3 4 5 6 7) [5 6 7])
就性能而言,第一个解决方案应该运行得更快一些

(定义查找索引)
(defn find-index
  "find index of the first item in s matching predicate `pred`"
  [pred s]
  (first (keep-indexed (fn [index item]
                         (if (pred item)
                           index
                           nil))
                       s)))

(defn update-first-match
  "update first item in s that matches `pred` using (f item args*)"
  [s pred f & args]
  (apply update-in s [(or (find-index pred s)
                          (count s))]
         f args))


(def my-lists
  ['(2 3 4) '(4 5 6 7) '(5 6 7)])

(defn add-to-first-list-less-than
  [l n]
  (update-first-match l #(< n (first %)) conj n))

;; usage:

(update-first-match my-lists #(< 5 (first %)) conj 5)

;; or
(add-to-first-list-less-than my-lists 5)
“在匹配谓词'pred'中查找第一项的索引” [pred s] (首先(保持索引)(fn[索引项] (如有)(预测项目) 指数 (零) s) )) (defn更新第一个匹配 “使用(f项参数*)更新s中与'pred'匹配的第一项” [s pred f&args] (在s[(或(查找索引pred s)中应用更新) (s)] f(args)) (定义我的列表) ['(2 3 4) '(4 5 6 7) '(5 6 7)]) (定义添加到第一个列表中的时间少于 [l n] (更新第一个匹配项l#(
您以前的懒惰顺序:

(defn add-to-first-match
  [pred x coll]
  (lazy-seq
    (if-let [s (seq coll)]
      (let [fst (first s)]
        (if (pred fst)
          (cons (conj fst x) (rest s))
          (cons fst (add-to-first-match pred x (rest s)))))
      (cons (list x) nil))))

注意:可以进一步将
列表
提取到参数中,并允许例如
向量
作为元素构造函数。

以下是我尝试使用reduce更简洁地回答的问题:

(defn add-to-first-list-that-matches
  [value lists]
  (let [pred (comp (partial < value) first)
        [found result] (reduce (fn [[found result] el]
                                 (if (and (not found) (pred el))
                                   [true (conj result (cons value el))]
                                   [found (conj result el)]))
                               [false []]
                               lists)]
    (if found
      result
      (conj result (list value)))))

带答案的拆分非常简洁。我不知道如何感谢S拆开,但请记住,它需要两个懒惰遍历的LL,因为它等于[(当PrD当Prdll)(下降,而Prdll)](你认为性能影响的原因不使用你的分裂与方法?对我来说,这似乎是最优雅的解决方案,因为没有太多的“列表处理”代码(如循环或减少)涉及。这取决于你想要实现什么。如果你正在处理一个更大的序列,使用split遍历它两次,代价是RH称之为“每一步分配开销”。当我尝试最大化性能时,我从不使用split-with。谢谢。另外,我觉得很有趣,你称他为RH:)你也可以写(当(pred item)index)在第5行。@user1944838我真的不喜欢使用(when…)作为纯表达式;我只喜欢使用(when…)对于副作用调用。我从来没有听说过这个习惯用法。你能详细说明一下吗?但是,你仍然可以放弃nil。这比我的循环递归性能更好。很好。在这个示例中,使用惰性seq(而不是仅仅从if表达式开始,它也可以工作)有什么好处?这仅仅是为了性能吗?是的,如果只获取结果序列中的一个或两个元素,则不会为其他元素调用主体。结果有点记忆化,因此如果再次获取相同的元素,主体也不会再次被调用。所以性能是一样的,尽管我还是想要整个列表,但最好不要这样做o任何函数都会返回一个列表,因为你永远不知道到底需要多少列表?这正是我一开始想要解决它的方式。我只是不知道,reduce应该如何知道,我们是否已经增加了值。我是clojure的新手,所以我喜欢看到许多不同的方法,以及迄今为止我学到的一件事(在这个线程中)就是,销毁确实是一个经常使用的好东西。谢谢:)
(defn add-to-first-match
  [pred x coll]
  (lazy-seq
    (if-let [s (seq coll)]
      (let [fst (first s)]
        (if (pred fst)
          (cons (conj fst x) (rest s))
          (cons fst (add-to-first-match pred x (rest s)))))
      (cons (list x) nil))))
(defn add-to-first-list-that-matches
  [value lists]
  (let [pred (comp (partial < value) first)
        [found result] (reduce (fn [[found result] el]
                                 (if (and (not found) (pred el))
                                   [true (conj result (cons value el))]
                                   [found (conj result el)]))
                               [false []]
                               lists)]
    (if found
      result
      (conj result (list value)))))
user> (add-to-first-list-that-matches 3 ['(2 3 4) '(4 5 6 7) '(5 6 7)])
[(2 3 4) (3 4 5 6 7) (5 6 7)]
user> (add-to-first-list-that-matches 10 ['(2 3 4) '(4 5 6 7) '(5 6 7)])
[(2 3 4) (4 5 6 7) (5 6 7) (10)]