Reputation: 1053
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!
Upvotes: 5
Views: 172
Reputation: 106351
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]])))
Upvotes: 4
Reputation: 1339
I don't think your solution not clojure-ey too. But if you like less code you could try a sorted set.
(let [v [[0 0] [20 30] [-50 -70] [200 300]]
v-sorted (apply sorted-set v)]
[(first v-sorted) (last v-sorted)])
Update: I'm sorry the above code is not correct. It is neccessary to sort separetely x and y to find a bound not max or min points. John's solution is better unless sets is preferred.
Upvotes: 1
Reputation: 4224
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)])))
Upvotes: 3