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