What is the performance cost of converting between seqs and vectors?

Viewed 102

Many core Clojure functions return lazy sequences, even when vectors are passed into them. For example, if I had a vector of numbers, and wanted to filter them based on some predicate but get another vector back, I'd have to do something like this:

(into [] (filter my-pred my-vec))

Or:

(vec (filter my-pred my-vec))

Though I'm not sure if there's any meaningful difference between the two.

Is this operation expensive, or do you get it effectively for free, as when converting to/from a transient?

I understand that the seq is lazy so nothing will actually get calculated until you plop it into the output vector, but is there an overhead to converting from a seq and a concrete collection? Can it be characterized in terms of big-O, or does big-O not make sense here? What about the other way, when converting from a vector to a seq?

2 Answers

There's an FAQ in the Clojure site for good use cases for transducers, which could be handy for some complex transformations (more than just filtering, or when the predicate is fairly complex). Otherwise you can leverage on filterv, which is on the core library and you can assume it does any reasonable optimization for you.

TL;DR Don't worry about it


Longer version:

  1. The main cost is memory allocation/GC. Usually this is trivial. If you have too much data to fit simultaneously in RAM, the lazy version can save you.

  2. If you want to measure toy problems, you can experiment with the Criterium library. Try powers of 10 from 10^2 up to 10^9.

(crit/quick-bench (println :sum (reduce + 0 (into [] (range (Math/pow 10 N))))))

for N=2..9 with and without the (into [] ...) part.

Related