How do I write a Clojure function that returns a list of contiguous pairs?
I am trying to write a function adjacents
that returns a vector of a neighboring pair of sequences. Therefore, it (adjacents [1 2 3])
will 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 lines, but with integers or characters, the REPL throws this error:
IllegalArgumentException Don't know how to create ISeq from: java.lang.Long clojure.lang.RT.seqFrom (RT.java:494)
source to share
The problem here is in the first evaluation cycle (adjacents [1 2 3])
, a
tied to 1
and b
to 2
. Then you ask if there is b
empty?
. But it empty?
works on sequences, b
not a sequence, it is Long
, namely 2
. The predicate you can use for this case 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 not produce the desired result if you have the legitimate ones nil
in your data:
user=> (adjacents [1 2 nil 4 5])
[[1 2]]
See his comment on the proposed implementation using lists.
Note that Clojure partition
can be used to do this job without the dangers 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))
source to share
Here is my short answer. Everything becomes a vector, but it works for all sequences.
(defn adjacent-pairs [s]
{:pre [(sequential? s)]}
(map vector (butlast s) (rest s)))
Testing:
user=> (defn adjacent-pairs [s] (map vector (butlast s) (rest s)))
#'user/adjacent-pairs
user=> (adjacent-pairs '(1 2 3 4 5 6))
([1 2] [2 3] [3 4] [4 5] [5 6])
user=> (adjacent-pairs [1 2 3 4 5 6])
([1 2] [2 3] [3 4] [4 5] [5 6])
user=>
This answer is probably less efficient than the one used partition
above.
source to share