我想编写一个在向量中的现有元素之间插入元素的函数。插入的元素是前面和后面的元素的函数,第一个和最后一个元素保持不受影响。
E.g。我希望插入的元素是前面和后面的元素的平均值:
输入:
[1 10 15]
输出:
[1 5.5 10 12.5 15]
在Clojure中执行此操作的最佳方法是什么?
答案 0 :(得分:4)
这是另一种方式:
(defn insert-mean-between [xs]
(let [f (fn [x y]
[(* (+ x y) 0.5) y])]
(->> xs
(partition 2 1)
(mapcat (partial apply f))
(cons (first xs))
vec)))
(insert-mean-between [1 10 15])
;;=> [1 5.5 10 12.5 15]
主技巧是f
正在返回答案和RHS输入。这样,他们将在没有重复的情况下组合在一起。您将遇到的唯一问题是缺少第一个元素。所以我们只是把它放在前面。从一开始我们就必须知道,当我们选择返回RHS而不是LHS时,cons
将是一个方便的操作。
计算均值只是一个例子,一个改进的解决方案是插入独立于均值/任何函数:
(defn calc-mean [x y] (* (+ x y) 0.5)
(insert-between calc-mean [1 10 15])
然后更通用的插入功能可能是:
(defn insert-between [g xs]
(->> xs
(partition 2 1)
(mapcat (fn [[x y]] [(g x y) y]))
(cons (first xs))))
答案 1 :(得分:4)
并且在没有递归延迟序列生成的情况下,变体列表不会完整:
(defn with-avg [[x1 & [x2 :as tail] :as items]]
(when (seq items)
(if (seq tail)
(lazy-cat [x1 (/ (+ x1 x2) 2)] (with-avg tail))
[x1])))
user> (with-avg [1 2 3 4 5])
;;=> (1 3/2 2 5/2 3 7/2 4 9/2 5)
user> (with-avg [1])
;;=> [1]
user> (with-avg [])
;;=> nil
user> (with-avg [1 2])
;;=> (1 3/2 2)
user> (with-avg [1 2 3])
;;=>(1 3/2 2 5/2 3)
答案 2 :(得分:0)
我可以解决的一种方法是将模式匹配Vector
设为f s t
,我假设它有3个元素
然后创建变量以分配第一个中位数first + second / 2
和第二个中位数second + third /2
。
最后返回一个新的Vector
,其中包含您想要的组合。
示例,(我使用lein REPL )
user=> (defn insert_medians[vect]
#_=> (let [[f s t] vect
#_=> m1 (float (/ (+ f s) 2))
#_=> m2 (float (/ (+ s t) 2))]
#_=> [f m1 s m2 t]))
#'user/insert_medians
user=> (insert_medians [1 10 15])
[1 5.5 10 12.5 15]
如果矢量大于3个元素,则需要先找到所有中位数,然后使用interleave
fn插入原始矢量。
答案 3 :(得分:0)
(defn insert-between
"Inserts elements between existing elements in a vector v. The inserted
elements are a result of applying the function f to the elements that precede
and succeed it, with the first and last elements of v remaining unaffected."
[f [x & xs :as v]]
(->> (partition 2 1 v)
(mapcat (fn [[a b]] [(f a b) b]))
(cons x)
(into [])))
(defn mean [& numbers]
(float (/ (apply + numbers) (count numbers))))
(insert-between mean [1 10 15]) ; => [1 5.5 10 10 12.5 15]
(insert-between + [1 10 15 20 25]) ; => [1 11 10 25 15 35 20 45 25]
(insert-between mean []) ; => [nil] :(