Clojure从循环返回值



我想计算交点。这很好,但我想将点存储在函数应该返回的向量中。

这是我的代码:


(defn intersections
[polygon line]
(let [[p1 p2] line
polypoints (conj polygon (first polygon))]
(doseq [x (range (- (count polypoints) 1))]
(println  (intersect p1 p2 (nth polypoints x) (nth polypoints (+ x 1))))
)))

我想将结果添加到应该返回的新向量中,而不是println。我该怎么改?

您需要使用for循环。doseq函数仅用于副作用,并且始终返回nil。一个例子:

(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test))
(defn intersect-1
[numbers]
(let [data-vec (vec numbers)]
(vec
(for [i (range (dec (count numbers)))]
{:start (nth data-vec i)
:stop  (nth data-vec (inc i))}))))

如单元测试所示,上述方法有效:

(dotest
(is= (intersect-1 (range 5))
[{:start 0, :stop 1}
{:start 1, :stop 2}
{:start 2, :stop 3}
{:start 3, :stop 4}])

然而,在Clojure:中这样写更自然

(defn intersect-2
[numbers]
(let [pairs (partition 2 1 numbers)]
(vec
(for [[start stop] pairs]
{:start start :stop  stop} ))))

结果相同

(is= (intersect-2 (range 5))
[{:start 0, :stop 1}
{:start 1, :stop 2}
{:start 2, :stop 3}
{:start 3, :stop 4}]))

你可以获得我最喜欢的模板项目的更多细节(包括一个大的文档列表!(。特别是看Clojure CheatSheet!

旁注vec在两个版本中都是可选的。这只是将答案强制转换为Clojure向量(而不是"lazy-seq"(,这在示例和单元测试中更容易剪切和粘贴。

与其使用for循环,不如使用map

(defn intersections
[polygon line]
(let [[p1 p2] line]
(vec (map (fn [pp1 pp2] (intersect p1 p2 pp1 pp2)) polygon (cdr polygon)))))

或:

(defn intersections
[polygon line]
(let [[p1 p2] line]
(vec (map #(intersect p1 p2 %1 %2) polygon (cdr polygon)))))

最新更新