Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

getting the bounds of a list of x,y points

Tags:

clojure

I have a list of x,y points stored as a vector of vectors, and I want to find out the bounds.

For example, given this:

[[0 0] [20 30] [-50 -70] [200 300]]

The result would be:

{:x -50, :y -70, :x2 200, :y2 300}

Here's what I have so far. It gives the desired result, but seems verbose and not very clojure-ey to me.

(defn get-stroke-bounds [vector-of-points]
  (reduce (fn [m [x y]]
        {:x  (min (:x  m Integer/MAX_VALUE) x)
         :y  (min (:y  m Integer/MAX_VALUE) y)
         :x2 (max (:x2 m Integer/MIN_VALUE) x)
         :y2 (max (:y2 m Integer/MIN_VALUE) y)})
      {}
      (vector-of-points)))

Any ideas on how to improve it? Thanks!

like image 540
jhickner Avatar asked Jul 06 '11 18:07

jhickner


2 Answers

Your solution is already pretty good! It's fairly idiomatic and is also O(n) in the number of points which is algorithmically optimal (better in fact than a method which does a sort).

But here's an alternative way of doing it you might find interesting.... created mainly because I'm a big fan of higher order functions :-)

(defn get-stroke-bounds [stroke]
     (zipmap
       [:x :y :x2 :y2]
       (map
         (fn [[getter reducer]]
           (reduce 
             reducer
             (map getter stroke)))
         [
          [first min]
          [second min]
          [first max]
          [second max]])))
like image 97
mikera Avatar answered Oct 10 '22 00:10

mikera


If I am already using vectors for the input points, I'd want the return value to be in the same format. With that in mind, I think this is a good idiomatic solution:

(defn bounds
  [points]
  (let [xs (sort (map first points))
        ys (sort (map second points))]
    (list [(first xs) (first ys)]
          [(last xs) (last ys)])))
like image 27
John Cromartie Avatar answered Oct 10 '22 00:10

John Cromartie