Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/selenium/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Clojure 仅更新coll中与pred匹配的第一个元素的惯用方法_Clojure - Fatal编程技术网

Clojure 仅更新coll中与pred匹配的第一个元素的惯用方法

Clojure 仅更新coll中与pred匹配的第一个元素的惯用方法,clojure,Clojure,我有一个序列,(def coll'([:a20][:b30][:c50][:d90]) 我想遍历seq,只修改与谓词匹配的第一个元素 谓词(def pred(fn[[ab]](>b30)) (fpred(fn[[ab]][a(+b2)]coll)=>([:a20][:b30][:c52][:d90]) f是我想要的fn,它取一个pred,一个fn应用于匹配pred的第一个元素。所有其余元素均未修改并返回到seq中 做上述工作的惯用方法是什么?与大多数问题一样,有许多方法可以解决。这只是其中之一

我有一个序列,
(def coll'([:a20][:b30][:c50][:d90])

我想遍历seq,只修改与谓词匹配的第一个元素

谓词
(def pred(fn[[ab]](>b30))

(fpred(fn[[ab]][a(+b2)]coll)=>([:a20][:b30][:c52][:d90])

f是我想要的fn,它取一个pred,一个fn应用于匹配pred的第一个元素。所有其余元素均未修改并返回到seq中


做上述工作的惯用方法是什么?

与大多数问题一样,有许多方法可以解决。这只是其中之一

如果您正在运行Clojure 1.5,请尝试一下:

(reduce
 (fn [acc [a b]]
   (if (pred b)
     (reduced (concat (:res acc) [[a (+ b 2)]] (rest (:coll acc))))
     (assoc acc
       :res (conj (:res acc) [a b])
       :coll (rest (:coll acc)))))
 {:coll coll :res []}
 coll)

;; ([:a 20] [:b 30] [:c 52] [:d 90])
该算法的关键是使用
reduced
(注意“d”)函数-它本质上告诉
reduce
停止迭代并返回结果。从其文档字符串:

-------------------------
clojure.core/reduced
([x])
  Wraps x in a way such that a reduce will terminate with the value x
代码有点简洁,但它应该给你基本的想法


希望这有帮助。

一种可能的方法是使用
拆分
来拆分集合,将函数
f
应用于
拆分
返回的第二个集合的第一个元素,然后将这些元素再次合并

(defn apply-to-first [pred f coll]
    (let [[h t] (split-with (complement pred) coll)]
        (concat h (list (f (first t))) (rest t))))
请注意,示例中的
pred
函数可能如下所示:

(def pred #(> (second %) 30))

为了保持简单:找到第一个元素,找到它的索引,并使用assoc“更新”索引处的元素:

(let [e (first (filter pred coll))
      ind (.indexOf coll e)] 
  (assoc (vec coll) ind ((fn [[a b]] [a (+ b 2)]) e) ))
多米尼克关于pred的说明适用于:

(def pred #(> (second %) 30))

这个函数不难“从头开始”递归编写。这不仅是一个很好的学习练习,它还产生了最好的解决方案:它尽可能地懒惰,并且计算量绝对最小。到目前为止,这个问题只有一个答案是懒惰的,
pred
在更新发生之前对所有项目调用两次:一次在
take while
中,一次在
drop while
中,部分
分离

(defn update-first [pred f coll]
  (lazy-seq
   (when-let [coll (seq coll)]
     (if (pred (first coll))
       (cons (f (first coll))
             (rest coll))
       (cons (first coll)
             (update-first pred f (rest coll)))))))

好处:这个解决方案是懒惰的。