Accessing elements of array based on indices given by another array - arrays

Suppose I have the following 4x4 Array in Julia:
julia> A=rand(4,4)
4×4 Array{Float64,2}:
0.00624508 0.624399 0.458094 0.341848
0.303817 0.269487 0.580949 0.534655
0.748525 0.419411 0.469938 0.659914
0.730659 0.191461 0.996144 0.74772
And I have another 6x2 Array where each row represents a row-column pair:
julia> B=[ 1 1; 1 3; 2 2; 2 4; 3 1; 3 3]
6×2 Array{Int64,2}:
1 1
1 3
2 2
2 4
3 1
3 3
The first row of B represents the element [1,1] of A, the second row of B represents the element [1,3] of A, and so on. I want to access the elements of A based on the coordinates given by each row of B. In R for example, the command A[B] gives exactly what I want: 0.00624508 0.458094 0.269487 0.534655 0.748525 0.469938 but in Julia, the same command gives
julia> A[B]
6×2 Array{Float64,2}:
0.00624508 0.00624508
0.00624508 0.748525
0.303817 0.303817
0.303817 0.730659
0.748525 0.00624508
0.748525 0.748525
and this is not what I want. Is there a similar way of coding A[B] in Julia, so that I obtain what I obtain in R? Must be applicable to any Array.

Construct an array of CartesianIndex out of your index pairs:
julia> A[CartesianIndex.(B[:, 1], B[:, 2])]
6-element Array{Float64,1}:
0.987200021334854
0.5261639427155012
0.8430528192705655
0.5300778835366697
0.5044387593056074
0.0025132074927423087
This is necessary to distinguish such "point indexing" from "shape indexing", as you observed it (I made those terms up).
Ideally, you would already construct B as such an array, but that is not always feasible, of course.

Related

Julia accessing specific Matrix elements using vectors as indexes

Suppose I have a 4*2 matrix as follows:
a = [1 2; 3 4; 5 6; 7 8]
4×2 Matrix{Int64}:
1 2
3 4
5 6
7 8
I want to access the matrix using a vector specifying which element I want to access in each column. In NumPy from python, I would do the following command:
a[[1,3], [1,2]]
# expected output:
1×2 Matrix{Int64}:
1(as a[1,1]) 6(as a[3,2])
but in Julia, I got the following matrix:
2×2 Matrix{Int64}:
1 2
5 6
How can I do it in an julia way?
UPDATE: Inspired by DNF answer:
julia> a[CartesianIndex.([1 3], [1 2])]
1×2 Matrix{Int64}:
1 6
seems to me the right balance of clarity and similarity to OP.
ORIGINAL answer:
Maybe not the optimal way, but:
[a[x...] for x in [[[1,1]] [[3,2]]]]
works.
Note that this returns a row vector, like in the OP. In Julia there is a difference between a vector and a matrix. A matrix with one row or one column is not the same as a vector.
The [[]] notation is to let hcat handle vector elements correctly. If a vector output is good enough, then: [[1,1],[3,2]] is enough.
The syntax a[i, j] is syntax sugar for getindex(a, i, j). You can broadcast getindex to get the desired behavior (unfortunately, you cannot broadcast the [] syntax itself):
getindex.(Ref(a), [1,3], [1,2])
You must protect a itself against being broadcasted, by wrapping it in a Ref.

Remove a value in an array and decrease the size of it

I have an array filled with some values. After running this code:
array = zeros(10)
for i in 1:10
array[i] = 2*i + 3
end
The array looks like:
10-element Array{Float64,1}:
5.0
7.0
9.0
11.0
13.0
15.0
17.0
19.0
21.0
23.0
I would like to obtain, for example, the following array by removing the third value:
9-element Array{Float64,1}:
5.0
7.0
11.0
13.0
15.0
17.0
19.0
21.0
23.0
How to do that?
EDIT
If I have an array (and not a vector), like here:
a = [1 2 3 4 5]
1×5 Array{Int64,2}:
1 2 3 4 5
The deleteat! proposed is not working:
a = deleteat!([1 2 3 4 5], 1)
ERROR: MethodError: no method matching deleteat!(::Array{Int64,2}, ::Int64)
You might have used a 2d row vector where a 1d column vector was required.
Note the difference between 1d column vector [1,2,3] and 2d row vector [1 2 3].
You can convert to a column vector with the vec() function.
Closest candidates are:
deleteat!(::Array{T,1} where T, ::Integer) at array.jl:875
deleteat!(::Array{T,1} where T, ::Any) at array.jl:913
deleteat!(::BitArray{1}, ::Integer) at bitarray.jl:961
I don't want a column vector. I would want:
1×4 Array{Int64,2}:
2 3 4 5
Is it possible ?
To make that clear: Vector{T} in Julia is just a synonym for Array{T, 1}, unless you're talking about something else... we call Arrays of all ranks arrays.
But this seems to be a Matlab-inherited misconception. In Julia, you construct a Matrix{T}, ie., an Array{T, 2}, by using spaces in the literal:
julia> a = [1 2 3 4 5]
1×5 Array{Int64,2}:
1 2 3 4 5
Deleting from a matrix does not make sense in general, since you can't trivially "fix the shape" in a rectangular layout.
A Vector or Array{T, 1} can be written using commas:
julia> a = [1, 2, 3, 4, 5]
5-element Array{Int64,1}:
1
2
3
4
5
And on this, deleteat! works:
julia> deleteat!(a, 1)
4-element Array{Int64,1}:
2
3
4
5
For completeness, there's also a third variant, the RowVector, which results of a transposition:
julia> a'
1×4 RowVector{Int64,Array{Int64,1}}:
2 3 4 5
From this you also can't delete.
Deleteat! is only defined for:
Fully implemented by:
Vector (a.k.a. 1-dimensional Array)
BitVector (a.k.a. 1-dimensional BitArray)
A Row Vector (2 Dimensions) won't work.
But ... there is a workaround by this trick:
julia> deleteat!(a[1,:], 1)' # mind the ' -> transposes it back to a row vector.
1×4 RowVector{Int64,Array{Int64,1}}:
2 3 4 5
Ofcourse this wouldn't work for an Array with 2 or more rows.

The best way to convert Vector into Matrix in Julia?

Suppose I have a variable v of a type Vector.
What would be the best / fastest way to just convert it into Matrix representation (for whatever reason)?
To clarify, v'' will do the job, but is it the best way to do this?
Reshape should be the most efficient. From the docs:
reshape(A, dims): Create an array with the same data as the given array, but with different dimensions. An implementation for a particular type of array may choose whether the data is copied or shared.
julia> v = rand(3)
3-element Array{Float64,1}:
0.690673
0.392635
0.0519467
julia> reshape(v, length(v), 1)
3x1 Array{Float64,2}:
0.690673
0.392635
0.0519467
v[:,:] is probably the clearest way to do this.
For example:
julia> v=[1,2,3]
3-element Array{Int64,1}:
1
2
3
julia> m=v[:,:]
3x1 Array{Int64,2}:
1
2
3
julia> ndims(m)
2
Or just use:
v = [1, 2, 3]
hcat(v)
Result:
3×1 Array{Int64,2}:
1
2
3

Error when adding 2-D array and 2-D subarray of 3-D array in Julia

Why does Julia throw an error when I run the following code?
After all, A[1,:,:] is logically a 2-D array.
If I remember correctly, similar code would have worked in MATLAB.
julia> A = reshape(1:8, 2, 2, 2)
2x2x2 Array{Int64,3}:
[:, :, 1] =
1 3
2 4
[:, :, 2] =
5 7
6 8
julia> B = reshape(1:4, 2, 2)
2x2 Array{Int64,2}:
1 3
2 4
julia> B + A[1,:,:]
ERROR: dimensions must match
in promote_shape at operators.jl:211
in promote_shape at operators.jl:207
in + at array.jl:723
Using A and B as defined in your question, note that:
ndims(B)
ndims(A[1,:,:])
returns 2 and 3 respectively. So a sum operation fails because B is a matrix while A[1,:,:] is a 3-dimensional array. Specifically, A[1,:,:] is 1x2x2. The solution is to squeeze the first dimension like so:
B + squeeze(A[1,:,:], 1)
I can see the source of the confusion here. I'm guessing you noticed that:
B[1, :]
returns type Vector, and you assumed the same principle of automatic squeezing would apply to a higher-dimensional array. The github issues page where the questions surrounding this kind of behaviour were settled is here. Interesting read.

Julia Reverse N-dimensional arrays

In Python, Numpy arrays can be reversed using the standard [::-1] i.e.
A = np.diag(np.arange(1,3))
A[::, ::-1]
A[::-1]
A[::-1, ::-1]
Julia does not support [::-1] and the reverse method only works on 1D arrays and only 1D columns (where as rows are 2D by default).
Is there an alternative I'm missing?
Try the following, which is essentially the same as the numpy version:
julia> X = rand(3,3)
3x3 Array{Float64,2}:
0.782622 0.996359 0.335781
0.719058 0.188848 0.985693
0.455355 0.910717 0.870187
julia> X[end:-1:1,end:-1:1]
3x3 Array{Float64,2}:
0.870187 0.910717 0.455355
0.985693 0.188848 0.719058
0.335781 0.996359 0.782622
In Julia 1.0, to reverse a (column) vector:
julia> reverse([1, 2, 3])
3-element Array{Int64,1}:
3
2
1
For reversing rows, just state that you want to flip the second dimension:
julia> reverse([1 2 3], dims=2)
1×3 Array{Int64,2}:
3 2 1
EDIT: Alternatively, you can also index in reverse using end:-1:1, and that way also allows you to request a view instead of a copy:
julia> a = reshape(randperm(9), 3, 3)
3×3 Matrix{Int64}:
4 7 9
5 2 1
3 6 8
julia> #view a[:, end:-1:1]
3×3 view(::Matrix{Int64}, :, 3:-1:1) with eltype Int64:
9 7 4
1 2 5
8 6 3
Following up #IainDunning's answer, an important difference between numpy and Julia here is that X[:,end:-1:1] in Julia returns a copy and in numpy X[:,::-1] will return a view of the same data (no copy is made).
I'm just learning Julia myself, but it seems like you can accomplish something similar in Julia using sub(X, :, size(X)[2]:-1:1), which returns Julia's equivalent of a view (SubArray). Interestingly, you can't use the end keyword in this construct as far as I can see, and instead you must pass in the actual end index in the dimension.
You can use the function flipdim(mat, d).
Ref: http://docs.julialang.org/en/release-0.4/stdlib/arrays/
Try this set of functions:
function reverser(x::AbstractArray, dims::AbstractVector{<:Integer})
y = copy(x)
for d in dims
y = reverse(y, dims=d)
end
return y
end
reverser(x::AbstractArray) = reverser(x, 1:ndims(x)) # all dimensions
reverser(x::AbstractArray, d::Integer) = reverser(x, [1])
Julia 1.6 supports reversing any or all of the dimensions of an arbitrary multidimensional array (implemented here). To reverse all of the dimensions, you can simply do reverse(X).

Resources