Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is is possible to destructure a clojure vector into last two items and the rest?

I know I can destructure a vector "from the front" like this:

(fn [[a b & rest]] (+ a b))

Is there any (short) way to access the last two elements instead?

(fn [[rest & a b]] (+ a b)) ;;Not legal

My current alternative is to

(fn [my-vector] (let [[a b] (take-last 2 my-vector)] (+ a b))) 

and it was trying to figure out if there is way to do that in a more convenient way directly in the function arguments.

like image 296
RubenLaguna Avatar asked Dec 08 '15 23:12

RubenLaguna


2 Answers

user=> (def v (vec (range 0 10000000)))
#'user/v
user=> (time ((fn [my-vector] (let [[a b] (take-last 2 my-vector)] (+ a b))) v))
"Elapsed time: 482.965121 msecs"
19999997
user=> (time ((fn [my-vector] (let [a (peek my-vector) b (peek (pop my-vector))] (+ a b))) v))
"Elapsed time: 0.175539 msecs"
19999997

My advice would be to throw convenience to the wind and use peek and pop to work with the end of a vector. When your input vector is very large, you'll see tremendous performance gains.

(Also, to answer the question in the title: no.)

like image 189
WolfeFan Avatar answered Nov 08 '22 07:11

WolfeFan


You can peel off the last two elements and add them thus:

((fn [v] (let [[b a] (rseq v)] (+ a b))) [1 2 3 4])
; 7
  • rseq supplies a reverse sequence for a vector in quick time.
  • We just destructure its first two elements.
  • We needn't mention the rest of it, which we don't do anything with.
like image 45
Thumbnail Avatar answered Nov 08 '22 05:11

Thumbnail