I would like to sort a primitive Java array using a custom Comparator, but I get a type error. I think the function comparator
creates Comparator<java.lang.Object>
, not Comparator<Long>
, but I can't figure out how to get around this.
Here is a minimal example:
x.core=> (def x (double-array [4 3 5 6 7]))
x.core=> (java.util.Arrays/sort x (comparator
ClassCastException [D cannot be cast to [Ljava.lang.Object; x.core/eval1524 (form-init5588058267991397340.clj:1)
I tried to add different types of hints to the comparator function, but frankly, I am relatively new to this language and basically just threw darts.
I intentionally simplified the above example to focus on the key question, which is a type error. In the following sections I will try to give more detailed information in order to motivate the question and demonstrate why I use a custom Comparator.
Motivation
, , R order
, :
> x = c(7, 2, 5, 3, 1, 4, 6)
> order(x)
[1] 5 2 4 6 3 7 1
> x[order(x)]
[1] 1 2 3 4 5 6 7
, , .
Clojure:
(defn order
"Permutation of indices sorted by x"
[x]
(let [v (vec x)]
(sort-by #(v %) (range (count v)))))
x.core=> (order [7 2 5 3 1 4 6])
(4 1 3 5 2 6 0)
( , R 1, Clojure 0). , ( , x [0, 1, ..., (count x)]
x.
R vs. Clojure
, . R :
> x = runif(1000000)
> system.time({ y = order(x) })
user system elapsed
0.041 0.004 0.046
Clojure :
x.core=> (def x (repeatedly 1000000 rand))
x.core=> (time (def y (order x)))
"Elapsed time: 2857.216452 msecs"
?
, R:
> x = runif(1000000)
> system.time({ y = sort(x) })
user system elapsed
0.061 0.005 0.069
.
x.core=> (def x (double-array (repeatedly 1000000 rand)))
x.core=> (time (java.util.Arrays/sort x))
"Elapsed time: 86.827277 msecs"
nil
java.util.Arrays. , R.
, Comparator ArrayList, , :
(defn order2
[x]
(let [v (vec x)
compx (comparator (fn [i j] (< (v i) (v j))))
ix (java.util.ArrayList. (range (count v)))]
(java.util.Collections/sort ix compx)
(vec ix)))
, Clojure. .: -)
Carcigenicate ,
(defn order
[x]
(let [ix (int-array (range (count x)))]
(vec (-> (java.util.Arrays/stream ix)
(.boxed)
(.sorted (fn [i j] (< (aget x i) (aget x j))))
(.mapToInt
(proxy [java.util.function.ToIntFunction] []
(applyAsInt [^long d] d)))
(.toArray)))))
:
x.core=> (def x (double-array [5 3 1 3.14 -10]))
x.core=> (order x)
[4 2 1 3 0]
x.core=> (map
(-10.0 1.0 3.0 3.14 5.0)
, . , , , .