如何解决将值添加到特定索引上的向量
我有一个函数可以在点列表之间细分一条线。
(defn subdivide [points]
(vec
(for [i (range (count points))]
(let [A (nth points i)
C (nth points (mod (inc i) (count points)))
x (/ (+ (first A) (first C)) 2)
y (/ (+ (second A) (second C)) 2)]
[x y] ))
))
目前我的返回值是新的 x 和 y 位置的列表。我怎样才能返回一个包含所有职位的列表。来自 A 的 x/y,来自 C 的新 x/y 和 x/y?所以我想在 A 和 C 之间的位置向量中注入新的 x/y。但是怎么做呢?
解决方法
您可以将索引为 i
的每条边映射到一对点:边的起点及其中点。然后连接结果。有一个特殊的映射和连接函数,mapcat。但是保留原始代码示例的 for
-宏,然后使用 (apply concat ...
将结果连接成一个惰性序列或使用 (into [] cat ...
连接成一个向量也可能会起作用。
(defn subdivide [points]
(mapcat (fn [i]
(let [A (nth points i)
C (nth points (mod (inc i) (count points)))
x (/ (+ (first A) (first C)) 2)
y (/ (+ (second A) (second C)) 2)]
[A [x y]]))
(range (count points))))
(subdivide [[0 0] [1 0] [0 1]])
;; => ([0 0] [1/2 0] [1 0] [1/2 1/2] [0 1] [0 1/2])
注意: 假设这些点形成一个循环,边从最后一个点到第一个点,此代码细分这些点。但是,如果不是这种情况,代码看起来不会有那么大的不同。
注意 2: 在某些惰性序列上使用 nth
的线性搜索可能存在隐藏的性能问题,但不确定。但在向量上,应该没问题。
你的函数完成了困难的部分。要将新的中间值“介于”现有值之间,可以使用一个库函数 - interleave:
所以我们接受你的函数:
from bokeh.palettes import Blues,Greens,Reds
cmaps = [Blues[256][200:],Greens[256][200:],Reds[256][200:]]
dims = ['rand1','rand2','rand3']
layout = hv.Layout([
rasterize(hv.Points(data_df,ds)).opts(cmap=c,width=1200,height = 400).hist(dims[1])
for c,ds in zip(cmaps,[['x',d] for d in dims])
])
link_selections(layout).cols(1)
或者我们可以使用基于库函数 (defn subdivide [points]
(vec (for [i (range (count points))]
(let [A (nth points i)
C (nth points (mod (inc i) (count points)))
x (/ (+ (first A) (first C)) 2)
y (/ (+ (second A) (second C)) 2)]
[x y] ))))
的一个:
partition
然后创建一个函数来将输入点与中间点的向量交错:
(defn subdivide [points]
(mapv #(conj []
(/ (+ (first (first %)) (first (second %))) 2)
(/ (+ (second (first %)) (second (second %))) 2))
(partition 2 1 (conj (vec points) (first points)))))
我认为最好将 (defn subdivide-and-interleave [points]
(butlast (interleave points (subdivide points))))
定义为单独的函数 - 这样您就可以在需要时单独调用 subdivide-and-interleave
函数。
请注意,这里我们删除了 subdivide
调用生成的最后一个元素,它表示 subdivide
向量的最后一个元素和第一个元素之间的中间点。如果您希望将其包含在结果中,您可以删除 points
调用。
这是使用我最喜欢的 template project 解决问题的一种方法。请务必仔细阅读 list of documentation,尤其是 Clojure CheatSheet。
(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test))
(defn interpolate-vals
[vals]
(let-spy
[val-pairs (partition 2 1 vals)
mid-vals (mapv
(fn [[a b]] (* 0.5 (+ a b))) ; destructure pair into values & compute avg
val-pairs)
mid-vals-sentinal (cons :dummy mid-vals) ; add a dummy element at front
result-sentinal (interleave mid-vals-sentinal vals)
result (vec (rest result-sentinal))]
result))
(dotest
(is= (interpolate-vals (range 5))
[0 0.5 1 1.5 2 2.5 3 3.5 4]))
let-spy
显示中间结果:
-------------------------------
Clojure 1.10.1 Java 15
-------------------------------
Testing tst.demo.core
val-pairs => ((0 1) (1 2) (2 3) (3 4))
mid-vals => [0.5 1.5 2.5 3.5]
mid-vals-sentinal => (:dummy 0.5 1.5 2.5 3.5)
result-sentinal => (:dummy 0 0.5 1 1.5 2 2.5 3 3.5 4)
result => [0 0.5 1 1.5 2 2.5 3 3.5 4]
Ran 2 tests containing 1 assertions.
0 failures,0 errors.
您可以使用相同的技术计算每对点的中点,然后构造一个新的输出向量。
替代答案:
如果您想使用更命令式的样式,您还可以使用 Tupelo 库中的 insert-at 函数:
(s/defn insert-at :- ts/List
"Inserts an element into a collection at the specified index."
[coll :- ts/List
index :- s/Int
elem :- s/Any]
...)
(is (= [9 0 1] (insert-at [0 1] 0 9)))
(is (= [0 9 1] (insert-at [0 1] 1 9)))
(is (= [0 1 9] (insert-at [0 1] 2 9)))
然而,这对于大序列来说会更慢,就像在 Java 中插入 List
的中间一样。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。