I'm trying to write a function adjacents
that returns a vector of a sequence's adjacent pairs. So (adjacents [1 2 3])
would return [[1 2] [2 3]]
.
(defn adjacents [s]
(loop [[a b :as remaining] s
acc []]
(if (empty? b)
acc
(recur (rest remaining) (conj acc (vector a b))))))
My current implementation works for sequences of strings but with integers or characters the REPL outputs this error:
IllegalArgumentException Don't know how to create ISeq from: java.lang.Long clojure.lang.RT.seqFrom (RT.java:494)
The problem here is in the first evaluation loop of (adjacents [1 2 3])
, a
is bound to 1
and b
to 2
. Then you ask if b
is empty?
. But empty?
works on sequences and b
is not a sequence, it is a Long
, namely 2
. The predicate you could use for this case here is nil?
:
user=> (defn adjacents [s]
#_=> (loop [[a b :as remaining] s acc []]
#_=> (if (nil? b)
#_=> acc
#_=> (recur (rest remaining) (conj acc (vector a b))))))
#'user/adjacents
user=> (adjacents [1 2 3 4 5])
[[1 2] [2 3] [3 4] [4 5]]
But, as @amalloy points out, this may fail to give the desired result if you have legitimate nil
s in your data:
user=> (adjacents [1 2 nil 4 5])
[[1 2]]
See his comment for suggested implementation using lists.
Note that Clojure's partition
can be used to do this work without the perils of defining your own:
user=> (partition 2 1 [1 2 3 4 5])
((1 2) (2 3) (3 4) (4 5))
user=> (partition 2 1 [1 2 nil 4 5])
((1 2) (2 nil) (nil 4) (4 5))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With