1

I want to calculate intersection points. This works well, but I want to store the points in a vector that the function should return.

Here is my code:


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

Instead of println I want to add the result to a new vector that should be returned. How can I change it?

2 Answers 2

6

You need to use a for loop. The doseq function is meant for side-effects only and always returns nil. An example:

(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))}))))

The above way works, as seen by the unit test:

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

However, it is more natural to write it like so in Clojure:

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

With the same result

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

You can get more details on my favorite template project (including a big documentation list!). See especially the Clojure CheatSheet!

Side note: The vec is optional in both versions. This just forces the answer into a Clojure vector (instead of a "lazy seq"), which is easier to cut and paste in examples and unit tests.

Sign up to request clarification or add additional context in comments.

1 Comment

thx a lot for your detailed answer. it helped me solve my problem and Unterstanding Clojure a bit more.
1

Instead of for-loop, a map would be more idiomatic.

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

or:

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.