By: Mosè Giordano
Re-posted from: http://giordano.github.io/blog/2020-05-23-random-array-indexing/
Image credit: “xkcd: Donald Knuth” (CC-BY-NC
2.5)
Let me introduce a package I recently wrote:
RandomBasedArrays.jl
, a
hassle-free package in the Julia programming language
for dealing with arrays. Every time you access an element of an array, the
first index is random, so this package relieves you from having to remember
whether Julia uses 0- or 1-based indexing: you simply cannot ever know what the
initial element will be. As an additional benefit, you can use any Int
to
index a RandomBasedArray
.
Motivation
This package takes a new stance in the longstanding debate whether arrays should
have 0-based or 1-based
indexing.
The main motivation for this package is that I’m sick of reading about this
debate. It is incredibly hard to convince people that there is no “one size
fits all” indexing in programming, both alternatives have their merits:
- 0-based indexing is natural every time you deal with offsets, e.g. when
referencing memory addresses, or when doing modular arithmetic - 1-based indexing is natural when you are counting elements: the 1st element is
“1”, the 2nd element is “2”, etc…
It is pointless to claim the superiority of one indexing over the other one, as
they’re useful in different situations.
As a matter of fact, many “math-oriented” languages (e.g., Fortran, Julia,
Mathematica, MATLAB, R), that are less likely to fiddle with pointers’
addresses, default to 1-based indexing, even though probably the majority of the
programming languages nowadays uses 0-based indexing.
Many people claim superiority of 0-based indexing over 1-based indexing because
of a popular note by Edsger
W. Dijkstra: “Why numbering
should start at
zero”.
However, I personally find this note unconvincing and partial, mainly based on
subjective arguments (like elegance and ugliness) rather than really compelling
reasons. That said, 0-based indexing is certainly useful in many situations.
A good programming language, whatever indexing convention it uses, should
provide an abstraction layer to let users forget which is the initial index.
For example, Fortran has lbound
to reference the first element of an array. Besides the
first
function to reference the first element of a collection, the Julia programming
language has different utilities to iterate over collections:
-
arrays are iterables, this means that you can write a
for
loop likefor element in my_array # do things with the `element`... end
without using indices at all
- the
length
function gives you the length of a collection, so that Dijkstra’s argument
about the length of a sequence remains aesthetic rather than practical eachindex
is
a function that returns an iterable object with all the indices of the array.
Some times you need to use the indices of an array and know which is the first
one. In this case, the abstraction layer above is not useful. Thus, I think it
is important for a programming language to provide also a way to easily switch
to the most appropriate indexing for the task at hand. In Fortran you can set a
different initial index for an array with the
dimension
statement. Julia allows you to define custom indices for you new array-like
type, as described in the
documentation. The
most notable application of custom indices is probably the
OffsetArrays.jl
package.
Other use cases of custom indices are shown in this blog
post.
Usage
Let’s come to RandomBasedArrays.jl
. You can install it with Julia built-in
package manager. In a Julia
session, after entering the package manager mode with ]
, run the command
pkg> add RandomBasedArrays
After that, just run using RandomBasedArrays
in the REPL to load the package.
It defines a new AbstractArray
type, RandomBasedArray
, which is a thin
wrapper around any other AbstractArray
.
julia> using RandomBasedArrays
julia> A = RandomBasedArray(reshape(collect(1:12), 3, 4))
3×4 Array{Int64,2}:
10 2 6 6
8 9 1 11
7 8 8 7
Every time you access an element, you conveniently get a random element of the
parent array, making any doubt about first index go away. This means that you
can use any Int
as index, including negative numbers:
julia> A[-35]
6
julia> A[-35]
9
julia> A[-35]
4
You can also set elements of the array in the usual way, just remember that
you’ll set a random element of the parent array:
julia> A[28,-19] = 42
42
julia> A
5×5 Array{Int64,2}:
13 16 3 25 9
23 20 16 18 1
5 17 21 6 8
5 3 42 10 13
25 6 23 4 11
julia> A
5×5 Array{Int64,2}:
9 25 25 3 3
4 14 9 7 18
22 14 13 21 2
11 12 19 14 19
19 2 21 2 21
Related projects
There are other Julia packages that play with different indexing of arrays, e.g.:
OffsetArrays.jl
:
Fortran-like arrays with arbitrary, zero or negative starting indicesTwoBasedIndexing.jl
:
Two-based indexing (note: this is currently out-of-date and doesn’t work in
Julia 1.0)