On Thursday, March 19, 2015 at 8:53:37 AM UTC-4, Henrik Heine wrote:
>
> Hi,
>
> I want to sort a set/map according to an ordering given by a seq of
> elements - e.g.
>
> (def some-order [:u :a :e :i :o])
> (def some-order-fn (order-fn some-order))
> (sorted-set-by some-order-fn :a :e :i :o :u) ; --> #{:u :a :e :i :o}
>
> This is what I came up with:
>
> (defn order-fn [ks]
> #(- (.indexOf ks %1)
> (.indexOf ks %2)))
>
This is going to do two inefficient linear searches on every lookup.
There's a fix for that, but it meshes so well with the rest of your request
that I'll post it below.
But then one may want to replace .indexOf for some other ord-function- like
> this:
>
> (defn order-fn
> ([ks] (order-fn ks #(.indexOf %1 %2)))
> ([ks ord-fn]
> #(- (ord-fn ks %1)
> (ord-fn ks %2))))
>
> Now we may force the elements to be present in ks:
>
> (defn order-fn
> ([ks] (order-fn ks #(.indexOf %1 %2)))
> ([ks ord-fn]
> (letfn
> [(-ord-fn [e]
> (let [o (ord-fn ks e)]
> (if (> o -1) o
> (throw
> (RuntimeException.
> (format "'%s' not found in %s" e ks))))))]
> #(compare (-ord-fn %1)
> (-ord-fn %2)))))
>
> Is there something like this in clojure.core already or a more elegant
> implementation?
>
I'd suggest the following.
First, for explicitly supplying an ord-fn:
(defn order-by
"Given a map or function with integer values, returns a comparison fn
that will order the keys by these values.
That function will throw an exception if passed an argument that's not a
key in the map, or for which the
passed map or function throws an exception or returns a nonnumeric
value."
[order-map]
(fn [x y]
(- (order-map x) (order-map y))))
And then, for ordering by a sequence:
(defn order-by-seq
"Given a sequential coll of keys, returns a comparison fn that will order
the keys per the sequence."
[order-seq]
(-> (map vector order-seq (range))
(into {})
(order-by)))
(NOTE: untested.)
Note that the lookups inside the comparator are O(1) hashmap lookups now,
rather than linear .indexOf lookups. And this version *should* also work in
CLJS and Clojure-CLR since it avoids host-specific interop and only uses
clojure.core functions.
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to [email protected]
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.