Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clojure: IllegalArgumentException Key must be integer

Tags:

clojure

I have two lists:

(def xxa ["olp" "xyz"])
(def xxb ["ulove" "alove" "holp" "sholp"])

and a function trying to get the elements of the 1st list that are parts of elements of the 2nd list:

(defn in-array
  [array1 array2]
  (for [s1 array1 :when (some #(.contains %1 s1) array2)] s1))

(in-array xxa xxb) should return ["olp"]

but I get:

IllegalArgumentException Key must be integer  clojure.lang.APersistentVector.invoke

I don't understand what that means. Can someone gives me some light?

like image 417
user3166747 Avatar asked Apr 28 '15 07:04

user3166747


1 Answers

Here's an attempt to make the discussion above into a clear answer for those who come along later. If I've missed something please let me know or edit:

Starting with the original example:

user> (def xxa ["olp" "xyz"])
#'user/xxa
user> (def xxb ["ulove" "alove" "holp" "sholp"])
#'user/xxb
user> (defn in-array [array1 array2]
        (for [s1 array1 :when (some #(.contains %1 s1) array2)] s1))
#'user/in-array

And then as peter points out, an extra set of () would cause this error:

user> (in-array (xxa xxb))
IllegalArgumentException Key must be integer  clojure.lang.APersistentVector.invoke (APersistentVector.java:284)

Which contains more code than is required to show the situation, so we can trim it down to:

user> (xxa xxb)
IllegalArgumentException Key must be integer  clojure.lang.APersistentVector.invoke (APersistentVector.java:284)

which is a minimal case to show the problem. If we change this example to pass the expected type we can see that vectors, when called as a function, take a number and look that number up in themselves.

user> (xxa 1)
"xyz"

So finally we can correct the call and get the expected output, almost exactly:

user> (in-array xxa xxb)
("olp")

The result is a (lazy) sequence from the for expression and user3166747 had asked for a vector (non lazy, and random access) which we can get by adding a call to vec:

user> (defn in-array [array1 array2]
        (vec (for [s1 array1 :when (some #(.contains %1 s1) array2)] s1)))
#'user/in-array

user> (in-array xxa xxb)
["olp"] 

and now it matches exactly.

like image 75
Arthur Ulfeldt Avatar answered Oct 13 '22 18:10

Arthur Ulfeldt