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)

      

+3


source to share


2 answers


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))

      

+4


source


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.

0


source







All Articles