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 resu开发者_如何转开发lt 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!
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]])))
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)])))
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.
精彩评论