Julia: Assignment in Arrays - multidimensional-array

When indexing more than one level for an array, it works fine. But when I used it to assign values, it did not. Does anyone know why A does not change below?
In [4]: A = rand(6)
Out [4]: 6-element Array{Float64,1}:
0.111552
0.155126
0.78485
0.147477
0.362078
0.959022
In [5]: A[3:5][[true,false,true]]
Out [5]: 2-element Array{Float64,1}:
0.78485
0.362078
In [6]: A[3:5][[true,false,true]] = [99, 999]
Out [6]: 2-element Array{Int64,1}:
99
999
In [7]: A
Out [7]: 6-element Array{Float64,1}:
0.111552
0.155126
0.78485
0.147477
0.362078
0.959022

This is because indexing arrays by ranges and vectors returns a new array with the output (instead of a view into the original array). Your statement is equivalent to the following:
julia> A = rand(6)
6-element Array{Float64,1}:
0.806919
0.445286
0.882625
0.556251
0.719156
0.276755
julia> B = A[3:5]
3-element Array{Float64,1}:
0.882625
0.556251
0.719156
julia> B[[true,false,true]] = [99, 999]
2-element Array{Int64,1}:
99
999
julia> A'
1x6 Array{Float64,2}:
0.806919 0.445286 0.882625 0.556251 0.719156 0.276755
julia> B'
1x3 Array{Float64,2}:
99.0 0.556251 999.0
You can actually see that this is what Julia is doing through some of its expression utilities. Note the explicit parentheses — it's calling setindex! on the result of indexing, which has made a copy. (GenSym() is an internal way of specifying a temporary variable):
julia> :(A[3:5][[true,false,true]] = [99, 999])
:((A[3:5])[[true,false,true]] = [99,999])
julia> expand(:(A[3:5][[true,false,true]] = [99, 999]))
:(begin
GenSym(0) = (top(vect))(99,999)
setindex!(getindex(A,colon(3,5)),GenSym(0),(top(vect))(true,false,true))
return GenSym(0)
end)
The goal is to eventually have all array indexing return views instead of copies, but that's still a work-in-progress.

Related

Get Type in Array

How can I get the type inside an array?
a = [1,2,3]
I can get the type of a
typeof(a)
Vector{Int64}
but I actually want Int64. First, I thought a newbie work-around could be
typeof(a[1])
Int64
but this is actually not correct, as can be seen here:
a = [1,2,3, missing]
typeof(a)
Vector{Union{Missing, Int64}}
The type of the vector is Union{Missing, Int64}, but the type of the first element is
typeof(a[1])
Int64
So, how do I get the type of the vector/array?
Use the eltype function:
julia> a = [1,2,3]
3-element Array{Int64,1}:
1
2
3
julia> eltype(a)
Int64
julia> a = [1,2,3, missing]
e4-element Array{Union{Missing, Int64},1}:
1
2
3
missing
julia> eltype(a)
Union{Missing, Int64}

How do we represent the Python/numpy function "zeros_like" in Julia language

I am a bit new to Julia but I have some knowledge in Python. I am now learning Julia and I want to know how to represent the Python function "zeros_like" from Numpy in Julia.
The python code is below:
import numpy as np
a = [3] #vector of one number
b = np.zeros_like(a)
Base.zero function returns the zero element (the "additive identity element" in the doc) for the type of its input argument:
julia> a = [3]
1-element Array{Int64,1}:
3
julia> zero(a)
1-element Array{Int64,1}:
0
or
julia> zeros(Int, size(a))
1-element Array{Int64,1}:
0

Assign vector components to different variables in Julia

I want to assign the result of an operation to a concatenation of variables in Julia. Something similar to this (although this doesn't work):
a = zeros(5)
b = zeros(5)
a, b .= rand(10)
Is it possible? Thank you.
You are looking for "vector view concatenation". The idea here is to use SubArrays to build an Array that is actually a view into two arrays. Julia does not support this out of the box. The Julia package ChainedVectors.jl was built for this, but it is heavily outdated and only works with Julia <= 0.4.
Not everything is lost. You have two alternatives:
Use CatViews.jl
As pointed out in the comments, CatViews.jl is like ChainedVectors.jl, but works with Julia 0.6 and 0.7:
Pkg.add("CatViews")
using CatViews
a = zeros(2)
b = zeros(2)
CatView(a, b) .= rand(4)
Build your own solution
With a little work, we can get as good as
a = zeros(2)
b = zeros(2)
MyView(a, b) .= rand(4)
Julia allows you to build your own view-concatenation type. The effort required to build it scales proportional to how general you want it to be. Here is a first attempt that works with vectors:
julia> # Create a type for a view into two vectors.
julia> type MyView{T} <: AbstractVector{T}
a::Vector{T}
b:: Vector{T}
end
julia> import Base: size, getindex, setindex!
julia> # Define methods to make MyView behave properly.
julia> size(c::MyView) = size(c.a) .+ size(c.b)
julia> getindex(c::MyView, i::Int) = i <= length(c.a) ? getindex(a, i) : getindex(b, i-length(a))
julia> setindex!(c::MyView, val, i::CartesianIndex) = i[1] <= length(c.a) ? setindex!(c.a, val, i[1]) : setindex!(c.b, val, i[1]-length(a))
julia> setindex!(c::MyView, val, i::Int) = i <= length(c.a) ? setindex!(c.a, val, i) : setindex!(c.b, val, i-length(a))
julia> # Test MyView. Define two arrays and put them
julia> # into a single view.
julia> a = rand(2)
2-element Array{Float64,1}:
0.701867
0.543514
julia> b = rand(2)
2-element Array{Float64,1}:
0.00355893
0.405809
julia> MyView(a, b) .= rand(4)
4-element MyView{Float64}:
0.922896
0.969057
0.586866
0.457117
julia> # Hooray, it worked! As we see below,
julia> # the individual arrays were updated.
julia> a
2-element Array{Float64,1}:
0.922896
0.969057
julia> b
2-element Array{Float64,1}:
0.586866
0.457117
This?
a .= x[1:5]
b .= x[6:end]
You must tell Julia somehow where to split the vector.

What functions are called to display an (Array) variable on the julia REPL?

Say I enter:
julia> X = randn(3,4)
3x4 Array{Float64,2}:
-0.862092 0.78568 0.140078 -0.0409951
-0.157692 0.0838577 1.38264 -0.296809
1.40242 -0.628556 -0.500275 0.258898
What functions were called to produce the output given?
Note that overloading Base.show does not seem to be sufficient to change this behaviour, so I'm unsure where to go.
julia> Base.show(io::IO, A::Array{Float64, 2}) = println("Humbug")
show (generic function with 120 methods)
julia> X
3x4 Array{Float64,2}:
-0.862092 0.78568 0.140078 -0.0409951
-0.157692 0.0838577 1.38264 -0.296809
1.40242 -0.628556 -0.500275 0.258898
Is it perhaps the case that I would have to change Base/array.jl source code and rebuild julia before such a change would work? Note the difference between this and a user defined type:
julia> type foo
x::Float32
s::ASCIIString
end
julia> ob = foo(1., "boo")
foo(1.0f0,"boo")
julia> Base.show(io::IO, someob::foo) = print("Humbug!")
show (generic function with 123 methods)
julia> ob
Humbug!
well, you should overload display():
julia> Base.display(A::Array{Float64, 2}) = println("Humbug")
display (generic function with 11 methods)
julia> X
Humbug
you can find the definition in REPL.jl.

Julia: check whether array entry is undef

What is the best way in Julia to check whether an array entry is #undef?
Example:
julia> a = Array(Vector,2)
julia> isdefined(a[1]) # fails
julia> isempty(a[1]) # fails
You can push the access into isdefined by using isdefined(a, 1) instead of isdefined(a[1]):
julia> a = Array(Vector,2);
julia> a[2] = {10}
1-element Array{Any,1}:
10
julia> a
2-element Array{Array{T,1},1}:
#undef
{10}
julia> isdefined(a[1])
ERROR: access to undefined reference
in getindex at array.jl:246
julia> isdefined(a, 1)
false
julia> isdefined(a, 2)
true

Resources