Any shortcut to 1:length(myVector)?

Is there any build-in function in Julia to replace 1:length(myVector), i.e. to return a vector of integers from 1 to the length of myVector ?

e.g.:

myVector =["a","b","c"]
for i in ???(myVector)
    println(i) # 1,2,3
end

There is eachindex.

julia> myVec = ["a","b","c"];

julia> for i in eachindex(myVec)
           println(i)
       end
1
2
3

Note, however, that this doesn’t necessarily give integers but whatever is appropriate/fast to index myVec with.

21 Likes

1:length is pretty short, just 8 characters. Also, it isn’t normally what you should be using, not for indexing, at least.

In a way, 1:length is a bit of an ad-hoc pattern, which probably shouldn’t have it’s own function, imho.

1 Like

There is also

for i in firstindex(x):lastindex(x)
   println(i)
end

which has the advantage of supporting offset arrays.

1 Like

Is this ever different from eachindex?

Apparently yes, it always returns integers (example adapted from here):

julia>  A = [1, 2, 3, 4];

julia> B = view(A,1:2,1:1)
2Ă—1 view(::Array{Int64,2}, 1:2, 1:1) with eltype Int64:
 1
 2

julia> for i in eachindex(B)
         println(i)
       end
CartesianIndex(1, 1)
CartesianIndex(2, 1)

julia> for i in firstindex(B):lastindex(B)
         println(i)
       end
1
2

3 Likes

Maybe LinearIndices, then:

for i in LinearIndices(B)
    println(i)
end

1
2
5 Likes

@leandromartinez98, for offset arrays, don’t we have to use pairs to obtain the offset indices? Example:

using OffsetArrays
A = [1 2 3; 4 5 6];
B = OffsetArray(A,-1:0,0:2)
for (i,) in pairs(B)
    println((i[1],i[2]))
end
(-1, 0)
(0, 0)
(-1, 1)
(0, 1)
(-1, 2)
(0, 2)

Afaik getindex(::OffsetArray, ::Int) works fine, it’s only OffsetVectors for which integer indexes are ambiguous. eachindex should always work, because it takes care of this, ie

julia> A = OffsetArray(1:2, 3:4)
1:2 with indices 3:4

julia> B = OffsetArray(reshape(1:6, 2, 3), -1:0, 0:2)
2Ă—3 OffsetArray(reshape(::UnitRange{Int64}, 2, 3), -1:0, 0:2) with eltype Int64 with indices -1:0Ă—0:2:
 1  3  5
 2  4  6

julia> eachindex(A)
OffsetArrays.IdOffsetRange(3:4)

julia> eachindex(B)
Base.OneTo(6)
3 Likes

I think things are getting mixed up here. But the OP wanted a way to obtain a vector of integers of the indexes of an array (I guess one-dimensional). firstindex and lastindex will do the job for offset arrays (as eachindex, but this one may return something that is not the indexes exactly, I am not sure how often and which are the collections for which that does not happen).

julia> using OffsetArrays

julia> x = OffsetArray([1, 2, 3],0:2)
3-element OffsetArray(::Array{Int64,1}, 0:2) with eltype Int64 with indices 0:2:
 1
 2
 3

julia> for i in firstindex(x):lastindex(x)
         println(i)
       end
0
1
2

By the way, although I think the OP knows that, the original question was how to obtain a vector of the indexes of an array.

Perhaps just for the sake of completeness:

julia> x = ["a","b","c"]
3-element Array{String,1}:
 "a"
 "b"
 "c"

julia> indexes = collect(eachindex(x))
3-element Array{Int64,1}:
 1
 2
 3


One thing that motivated my original mention of firstindex and lastindex was that I was not sure that eachindex necessarily returned the range in order. (the notation eachindex perhaps suggests that it does not, and that the iterations could occur out of order if that resulted to be more efficient for some reason. Apparently there is such guarantee?

There’s also enumerate(), which returns a tuple containing your incrementing index and the the value from myVector at that index. Useful if you’re wanting to both go through myVector and get the index for other reasons at the same time.

Note how I had to unpack the tuple in the for-loop with the ()'s around i and x.

myVector =["a","b","c"]
for (i, x) in enumerate(myVector)
    println("$i: $x")
end

# output:
# 1: a
# 2: b
# 3: c
2 Likes

I would like to note that enumerate documentation says:

An iterator that yields (i, x) where i is a counter starting at 1, and x is the ith value from the given iterator. It’s useful when you need not only the values x over which you are iterating, but also the number of iterations so far. Note that i may not be valid for indexing iter; it’s also possible that x != iter[i], if iter has indices that do not start at 1. See the pairs(IndexLinear(), iter) method if you want to ensure that i is an index.

So it has nothing to do with indexes, and it will give you incorrect index values if you are using any “non-vanilla” array. It is just a convenience for the cases in which you wanted to have a counter being incremented at each iteration.

3 Likes

This is slightly off topic but I have often used for (index,value) in enumerate(X) to create a loop where I need both the index and the value to work with. This has been fine for default arrays and I haven’t had an issue. It would be neat eventually to have a version that worked with arbitrarily indexed arrays by returning the value and the same indices returned by eachindex(X)

At the same time I’ve been reducing my usage of this pattern using broadcast and higher-ordered functions.

That’s pairs as noted above.

11 Likes

Thanks for the clarification. Hadn’t thought about that aspect of it.

(sorry, this was a reply to Henrique_Becker’s comment on my post.)

My fav (not yet mentioned) for i in axes(myVector,1)

6 Likes

Since functions are first class citizens in Julia, you can always create yours:

julia> inds(x) = firstindex(x):lastindex(x) |> collect;

julia> myVector =["a","b","c"];

julia> inds(myVector)
3-element Array{Int64,1}:
 1
 2
 3
1 Like

Mind blown, I knew about pairs but only had it in my mind in the context of Dictionaries. Using it for arrays is awesome!

I recently started to use keys for this:

for i in keys(myVector)
    ...
end

The added benefit is there is no need to touch that even if I change the underlying container type.

2 Likes

Note that if you don’t just need the indexes, but are lookup up the corresponding element (myVector[i]), pairs may be efficient for some collections.

1 Like