Welcome! Please see the About page for a little more info on how this works.

0 votes
in Clojure by

Hello Clojurians, I have a question on best practice for populating an array with a sequence of numbers.

This is not a seq structure. I'm referring to a mathematical sequence, e.g., 1, 2, 3, 4, 5, 6, 7, ..., n

My background is in statistical programming, so generating lists of numbers is suprisingly common, and useful!

In the R language, to produce an array of numbers you would do:

seq(1, 10) => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Or shorthand:

1:10 => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Either of these are considered idiomatic as they are readable and fast.

Assigning the array to a variable would then be:

nums = seq(1, 10)
nums => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

What is the Clojure way of doing this?

Unfortunately I am having trouble searching the web for a solution as, inevitably, any search including "sequence" brings one to https://clojuredocs.org/clojure.core/seq.

1 Answer

+1 vote
selected by
Best answer

You should use range:

(range 10)
; => (0 1 2 3 4 5 6 7 8 9)
Many thanks!
To complete the answer, if you want an indexed data structure (persistent) in this case with O(1) access, you can dump the result of `range` into a vector:

(vec (range 10))

Or if you want an actual mutable array,

(long-array (range 10))

Vectors are the idiomatic "persistent arraylist".  If you are doing a lot of random access or updates, then the vector will far outperform the sequence in practice since sequences are O(n) to get the nth entry (list performance), and they don't support an update operation out of the box like `assoc` which vectors do.

From the mathematical perspective  "This is not a seq structure. I'm referring to a mathematical sequence, e.g., 1, 2, 3, 4, 5, 6, 7, ..., n" is fairly meaningless in clojure, since all collections or iterables are seqable.  You can, for instance, trivially work with infinite sequences and only traverse or consume as much as is needed for the computation.  It's common to define algorithms this way (generate the possibly infinite sequence of all possible solutions, then filter that sequence, take from it, drop items, map onto it, etc., consume it until a result is found).  You can define generating functions as well (e.g. via `iterate`, or lower level implementations with `lazy-seq`).  Plenty of interesting ones in https://clojure.github.io/math.combinatorics/  .
While the original answer was sufficient, I have on occasion been using (vec (range ...)) since asking it for the reasons you described.

Had I enable email updates for ask.clojure.org, I would have seen your comment and probably been saved a bit of trouble. I shall do that now!

Thanks again.