How do I access the last element of an array? - julia

I want to access the last element of some array.
I am using length:
last_element = x[length(x)]
Is this correct? Is there a canonical way to access the last element of an ordered collection in Julia?

length is fine if your array uses standard indexing. However, x[length(x)] will not necessarily return the last element if the array uses custom indexing.
A more general and explicit method is to use last, which will return the last element of an array regardless of indexing scheme:
julia> x = rand(3)
3-element Array{Float64,1}:
0.7633644675721114
0.396645489023141
0.4086436862248366
julia> last(x)
0.4086436862248366
If you need the index of the last element, use lastindex:
julia> lastindex(x)
3
The following three methods are equivalent:
julia> last(x)
0.4086436862248366
julia> x[lastindex(x)]
0.4086436862248366
julia> x[end]
0.4086436862248366
x[end] is syntax sugar for x[lastindex(x)].

Related

Is there a Collection supertype between Set and Array? If not, how can a function be polymorphic over both Sets and Arrays (for iteration)?

Is there in Julia a Collection type from which both Set and Array derive ?
I have both:
julia> supertype(Array)
DenseArray{T,N} where N where T
julia> supertype(DenseArray)
AbstractArray{T,N} where N where T
julia> supertype(AbstractArray)
Any
And:
julia> supertype(Set)
AbstractSet{T} where T
julia> supertype(AbstractSet)
Any
What I try to achieve is to write function that can take both Array or Set as argument, because the type of collection doesn't matter as long as I can iterate over it.
function(Collection{SomeOtherType} myCollection)
for elem in myCollection
doSomeStuff(elem)
end
end
No, there is no Collection type, nor is there an Iterable one.
In theory, what you ask can be accomplished through traits, which you can read about elsewhere. However, I would argue that you should not use traits here, and instead simply refrain from restricting the type of your argument to the function. That is, instead of doing
foo(x::Container) = bar(x)
, do
foo(x) = bar(x)
There will be no performance difference.
If you want to restrict your argument types you could create a type union:
julia> ty = Union{AbstractArray,AbstractSet}
Union{AbstractSet, AbstractArray}
julia> f(aarg :: ty) = 5
f (generic function with 1 method)
This will work on both sets and arrays
julia> f(1:10)
5
julia> f(rand(10))
5
julia> f(Set([1,2,5]))
5
But not on numbers, for example
julia> f(5)
ERROR: MethodError: no method matching f(::Int64)
Closest candidates are:
f(::Union{AbstractSet, AbstractArray}) at REPL[2]:1

Why doesn't julia broadcasting work when deals with more than one array?

I have defined two structs and a function like this
struct A
x::Float64
end
struct B
y::Float64
end
f(a::A, b::B) = a.x*sin(b.y)
f.([A(0.1), A(0.2)], [B(1.), B(2.), B(3.)])
But f returns this error:
DimensionMismatch("arrays could not be broadcast to a common size")
How can I solve this error? I expect an array with 6 elements as the function output.
The problem is that your first argument is a 2-element Vector, and a second argument is 3-element Vector.
If you e.g. make the first argument a 1x2 Matrix, then all works fine:
julia> f.([A(0.1) A(0.2)], [B(1.), B(2.), B(3.)])
3×2 Array{Float64,2}:
0.0841471 0.168294
0.0909297 0.181859
0.014112 0.028224
(note that the missing or 1-length dimensions get automatically broadcasted)
Note that you could also broadcast calls to A and B constructors:
f.(A.([0.1 0.2]), B.(1.:3.))
The arrays have to have compatible dimensions - either identical in size and shape (local operations), or they span a larger vector space where each has singleton dimensions where the others have non-singleton dimensions, e.g. as an operation on the dimensions, the .* operator will cause the mapping
(1 x 1 x n) .* (p x q x 1) => p x q x n

Creating vector from two vectors in Julia

I have two vectors, say, x=[1;1] and y=[2;2]
I want to construct a vector whose element is a combination of these two, i.e. z=[[1,2],[1,2]]
What is the most efficient way to do that?
Just use zip. By default, this will create a vector of tuples:
julia> z = collect(zip(x,y))
2-element Array{Tuple{Int64,Int64},1}:
(1,2)
(1,2)
Note that this is different than what you wanted, but it'll be much more efficient. If you really want an array of arrays, you can use a comprehension:
julia> [[a,b] for (a,b) in zip(x,y)]
2-element Array{Array{Int64,1},1}:
[1,2]
[1,2]

Julia: append to an empty vector

I would like to create an empty vector and append to it an array in Julia. How do I do that?
x = Vector{Float64}
append!(x, rand(10))
results in
`append!` has no method matching append!(::Type{Array{Float64,1}}, ::Array{Float64,1})
Thanks.
Your variable x does not contain an array but a type.
x = Vector{Float64}
typeof(x) # DataType
You can create an array as Array(Float64, n)
(but beware, it is uninitialized: it contains arbitrary values) or zeros(Float64, n),
where n is the desired size.
Since Float64 is the default, we can leave it out.
Your example becomes:
x = zeros(0)
append!( x, rand(10) )
I am somewhat new to Julia and came across this question after getting a similar error. To answer the original question for Julia version 1.2.0, all that is missing are ():
x = Vector{Float64}()
append!(x, rand(10))
This solution (unlike x=zeros(0)) works for other data types, too. For example, to create an empty vector to store dictionaries use:
d = Vector{Dict}()
push!(d, Dict("a"=>1, "b"=>2))
A note regarding use of push! and append!:
According to the Julia help, push! is used to add individual items to a collection, while append! adds an collection of items to a collection. So, the following pieces of code create the same array:
Push individual items:
a = Vector{Float64}()
push!(a, 1.0)
push!(a, 2.0)
Append items contained in an array:
a = Vector{Float64}()
append!(a, [1.0, 2.0])
You can initialize an empty Vector of any type by typing the type in front of []. Like:
Float64[] # Returns what you want
Array{Float64, 2}[] # Vector of Array{Float64,2}
Any[] # Can contain anything
New answer, for Julia 1. append! is deprecated, you now need to use push!(array, element) to add elements to an array
my_stuff = zeros()
push!(my_stuff, "new element")

Initialize an array of arrays in Julia

I'm trying to create an array of two arrays. However, a = [[1, 2], [3, 4]] doesn't do that, it actually concats the arrays. This is true in Julia: [[1, 2], [3, 4]] == [1, 2, 3, 4]. Any idea?
As a temporary workaround, I use push!(push!(Array{Int, 1}[], a), b).
If you want an array of arrays as opposed to a matrix (i.e. 2-dimensional Array):
a = Array[ [1,2], [3,4] ]
You can parameterize (specify the type of the elements) an Array literal by putting the type in front of the []. So here we are parameterizing the Array literal with the Array type. This changes the interpretation of brackets inside the literal declaration.
Sean Mackesey's answer will give you something of type Array{Array{T,N},1} (or Array{Array{Int64,N},1}, if you put the type in front of []). If you instead want something more strongly typed, for example a vector of vectors of Int (i.e. Array{Array{Int64,1},1}), use the following:
a = Vector{Int}[ [1,2], [3,4] ]
In Julia v0.5, the original syntax now produces the desired result:
julia> a = [[1, 2], [3, 4]]
2-element Array{Array{Int64,1},1}:
[1,2]
[3,4]
julia> VERSION
v"0.5.0"
For a general answer on constructing Arrays of type Array:
In Julia, you can have an Array that holds other Array type objects. Consider the following examples of initializing various types of Arrays:
A = Array{Float64}(10,10) # A single Array, dimensions 10 by 10, of Float64 type objects
B = Array{Array}(10,10,10) # A 10 by 10 by 10 Array. Each element is an Array of unspecified type and dimension.
C = Array{Array{Float64}}(10) ## A length 10, one-dimensional Array. Each element is an Array of Float64 type objects but unspecified dimensions
D = Array{Array{Float64, 2}}(10) ## A length 10, one-dimensional Array. Each element of is an 2 dimensional array of Float 64 objects
Consider for instance, the differences between C and D here:
julia> C[1] = rand(3)
3-element Array{Float64,1}:
0.604771
0.985604
0.166444
julia> D[1] = rand(3)
ERROR: MethodError:
rand(3) produces an object of type Array{Float64,1}. Since the only specification for the elements of C are that they be Arrays with elements of type Float64, this fits within the definition of C. But, for D we specified that the elements must be 2 dimensional Arrays. Thus, since rand(3) does not produce a 2 dimensional array, we cannot use it to assign a value to a specific element of D
Specify Specific Dimensions of Arrays within an Array
Although we can specify that an Array will hold elements which are of type Array, and we can specify that, e.g. those elements should be 2-dimensional Arrays, we cannot directly specify the dimenions of those elements. E.g. we can't directly specify that we want an Array holding 10 Arrays, each of which being 5,5. We can see this from the syntax for the Array() function used to construct an Array:
Array{T}(dims)
constructs an uninitialized dense array with element type T. dims may be a tuple or a series of integer arguments. The syntax Array(T, dims) is also available, but deprecated.
The type of an Array in Julia encompasses the number of the dimensions but not the size of those dimensions. Thus, there is no place in this syntax to specify the precise dimensions. Nevertheless, a similar effect could be achieved using an Array comprehension:
E = [Array{Float64}(5,5) for idx in 1:10]
For those wondering, in v0.7 this is rather similar:
Array{Array{Float64,1},2}(undef, 10,10) #creates a two-dimensional array, ten rows and ten columns where each element is an array of type Float64
Array{Array{Float64, 2},1}(undef,10) #creates a one-dimensional array of length ten, where each element is a two-dimensional array of type Float64
You probably want a matrix:
julia> a = [1 2; 3 4]
2x2 Int64 Array:
1 2
3 4
Maybe a tuple:
julia> a = ([1,2],[3,4,5])
([1,2],[3,4,5])
You can also do {[1,2], [3,4]} which creates an Array{Any,1} containing [1,2] and [3,4] instead of an Array{Array{T,N},1}.

Resources