Probando si un objeto es una matriz primitiva de Java en Clojure

What's the best way to detect whether an object is a Java primitive array in Clojure?

The reason I need this is to do some special handling for primitive arrays, which might look something like:

  (if (byte-array? object)
    (handle-byte-array object))

It's in a fairly performance-sensitive piece of code so I'd rather avoid reflection if at all possible.

preguntado el 01 de febrero de 12 a las 03:02

Not sure what the Clojure code would be, but you could create an empty array for every primitive type, call getClass() on those, and cache the results. The Class object should be the same for every array of that primitive type – you'd compare the cached ones with object.getClass(). (getClass() shouldn't really be a slow call) -

7 Respuestas

you can use reflection once to get the class from the name, cache this and then compare the rest to that

(def array-of-ints-type (Class/forName "[I"))
(def array-of-bytes-type (Class/forName "[B")) 
...

(= (type (into-array Integer/TYPE [1 3 4])) array-of-ints-type)
true

Respondido 01 Feb 12, 08:02

Nice, like the idea of caching the primitive array classes. Though it does strike me as a bit off that these aren't already defined somewhere in Java! - mikera

"[J" para longs is even more endearing, isn't it? Also, whoever came up with the unmatched opening brackets in .toString return values, anytime I learn their name, my pitchfork will be ready. It breaks paredit for me all the time, not to mention the effect on my psyche. (Replacing print-method for all the relevant cases may or may not be feasible -- my current gut feeling is no.) - Michał Marczyk

(defn primitive-array? [o]
  (let [c (class o)]
    (and (.isArray c)
         (.. c getComponentType isPrimitive))))

For particular cases, you could use something like the following:

(defn long-array? [o]
  (let [c (class o)]
    (and (.isArray c)
         (identical? (.getComponentType c) Long/TYPE))))

Respondido 01 Feb 12, 08:02

To check for a byte array without the use of reflection you can do this:

(def ^:const byte-array-type (type (byte-array 0)))
(defn bytes? [x] (= (type x) byte-array-type))

Not exactly sure why, but you can even inline the byte-array-type with ^:const.

Respondido el 17 de diciembre de 13 a las 21:12

As pointed by Arthur Ulfeldt, you can use Class/forName, for example, like here:

(def byte_array_class (Class/forName "[B"))

(defn byte-array? [arr] (instance? byte_array_class arr))

If you want to avoid magic strings like "[B" when caching the classes, you can apply class to an existing array object:

(def byte_array_class (class (byte-array [])))

Respondido 20 Oct 12, 08:10

Aún más simple: (def byte-array-class (class (byte-array 0))). (No underscores either!) - David J.

Or plain old instance?:

(instance? (RT/classForName "[B") thing)

Respondido 01 Feb 12, 10:02

What alias are you using for RT? Te refieres a (Class/forName "[B") ¿derecho? - David J.

@DavidJames RT is clojure.lang.RT. - kotarak

Props to all the other answers. Here it is as a one-liner:

(def byte-array? (partial instance? (Class/forName "[B")))

For other primitives, refer to http://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#getName%28%29 (or the java spec). Or just do what Gerrit suggests with (type (xyz-array 0)). Specifically you can use:

"[Z" boolean array
"[B" byte array
"[C" char array
"[D" double array
"[F" float array
"[I" integer array
"[J" long array
"[S" short array

Since performance was mentioned, here's a small benchmark result of running (time (dotimes [_ 500000] (byte-array? x))), Y con byte-array-class def'd

(def byte-array? (partial instance? (Class/forName "[B")))
78.518335 msecs
(defn byte-array? [obj] (instance? byte-array-class obj))
34.879537 msecs
(defn byte-array? [obj] (= (type obj) byte-array-class))
49.68781 msecs

instance? vs type = instance? wins

partial vs defn = defn wins

but any of these approaches will likely not be a bottleneck in performance.

Respondido el 18 de junio de 15 a las 20:06

Since Clojure 1.9, you can use bytes? bytes? doc link

Respondido 13 Feb 19, 16:02

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.