how to extract 1x1 array slice as matrix in R? - arrays

I am working with 3D arrays. A function takes a 2D array slice (matrix) from the user and visualizes it, using row and column names (the corresponding dimnames of the array). It works fine if the array dimensions are > 1.
However, if I have 1x1x1 array, I cannot extract the slice as a matrix:
a <- array(1, c(1,1,1), list(A="a", B="b", C="c"))
a[1,,]
[1] 1
It is a scalar with no dimnames, hence part of the necessary information is missing. If I add drop=FALSE, I don't get a matrix but retain the original array:
a[1,,,drop=FALSE]
, , C = c
B
A b
a 1
The dimnames are here but it is still 3-dimensional. Is there an easy way to get a matrix slice from 1x1x1 array that would look like the above, just without the third dimension:
B
A b
a 1
I suspect the issue is that when indexing an array, we cannot distinguish between 'take 1 value' and 'take all values' in case where 'all' is just a singleton...

The drop parameter of [ is all-or-nothing, but the abind package has an adrop function which will let you choose which dimension you want to drop:
abind::adrop(a, drop = 3)
## B
## A b
## a 1

Without any extra packages, the best I could do was to apply and return the sub-array:
apply(a, 1:2, identity)
# or
apply(a, 1:2, I)
# B
#A b
# a 1

Related

Filling the array with array does not work as I expected

I want to make a multiple array whose entry is multiple array, and want to push some array one by one into the entry.
For example, I made 2 x 3 Matrix named arr and tried to fill [1,1] and [1,2] entries with 4 x 4 Matrix spawned by randn(4,4).
arr = fill(Matrix{Float64}[], 2, 3)
push!(arr[1,1],randn(4,4))
push!(arr[1,2],randn(4,4))
println(arr[1,1])
println(arr[1,2])
println(arr[1,3])
However, the result is all the entries of arr (other than [1,1] and [1,2]) were filled with the same randn(4,4), instead of just [1,1] and [1,2] filled with randn(4,4):
[[-0.15122805007483328 0.6132236453930502 -0.9090110366765862 1.2589924202099898; -1.120611384326006 -0.9083935218058066 0.7252290006516056 1.0970416725786256; -0.19173238706933265 1.3610525411901113 -0.05258697093572793 0.7776085390912448; 0.18491459001855373 -2.0537142669734934 0.3482557186126859 0.0047622478008474845], [0.23422967703060255 -0.51986351753462 0.45947166573674303 0.31316899298864387; 0.3704450103622709 -0.8186574197233013 -0.9990329964554037 -0.8345957519924763; 0.56641529964098 -0.8393435538481216 -0.6379336546939682 1.1843452368116358; 0.9435767553275002 0.0033471181565433127 -1.191611491619908 1.3970554854927264]]
[[-0.15122805007483328 0.6132236453930502 -0.9090110366765862 1.2589924202099898; -1.120611384326006 -0.9083935218058066 0.7252290006516056 1.0970416725786256; -0.19173238706933265 1.3610525411901113 -0.05258697093572793 0.7776085390912448; 0.18491459001855373 -2.0537142669734934 0.3482557186126859 0.0047622478008474845], [0.23422967703060255 -0.51986351753462 0.45947166573674303 0.31316899298864387; 0.3704450103622709 -0.8186574197233013 -0.9990329964554037 -0.8345957519924763; 0.56641529964098 -0.8393435538481216 -0.6379336546939682 1.1843452368116358; 0.9435767553275002 0.0033471181565433127 -1.191611491619908 1.3970554854927264]]
[[-0.15122805007483328 0.6132236453930502 -0.9090110366765862 1.2589924202099898; -1.120611384326006 -0.9083935218058066 0.7252290006516056 1.0970416725786256; -0.19173238706933265 1.3610525411901113 -0.05258697093572793 0.7776085390912448; 0.18491459001855373 -2.0537142669734934 0.3482557186126859 0.0047622478008474845], [0.23422967703060255 -0.51986351753462 0.45947166573674303 0.31316899298864387; 0.3704450103622709 -0.8186574197233013 -0.9990329964554037 -0.8345957519924763; 0.56641529964098 -0.8393435538481216 -0.6379336546939682 1.1843452368116358; 0.9435767553275002 0.0033471181565433127 -1.191611491619908 1.3970554854927264]]
What is wrong?
Any information would be appreciated.
When you do arr = fill(Matrix{Float64}[], 2, 3) all 6 elements point into exactly the same location in memory because fill does not make deep copy - it just copies the references. Basically, using fill when the first argument is mutable usually turns out not to be a good idea.
Hence what you actually want is:
arr = [Matrix{Float64}[] for i in 1:2, j in 1:3]
Now each of 6 slots will have its own address in the memory.
This way of creating the array implies that each element will be Float64, i.e. a scalar. You need to fix the type signature. So for instance you could do
D = Matrix{Array{Float64, 2}}(undef, 2, 3)
if you want it to have 2-dimensional arrays as elements (the Float64,2 does that)
and then allocate
D[1,1] = rand(4,4)
D[1,2] = rand(4,4)
to give you (or rather, me!):
julia> D[1,1]
4×4 Matrix{Float64}:
0.210019 0.528594 0.0566622 0.0547953
0.729212 0.40829 0.816365 0.804139
0.39524 0.940286 0.976152 0.128008
0.886597 0.379621 0.153302 0.798803
julia> D[1,2]
4×4 Matrix{Float64}:
0.640809 0.821668 0.627057 0.382058
0.532567 0.262311 0.916391 0.200024
0.0599815 0.17594 0.698521 0.517822
0.965279 0.804067 0.39408 0.105774

Correct way of maintaining array structure in R [duplicate]

I am working with 3D arrays. A function takes a 2D array slice (matrix) from the user and visualizes it, using row and column names (the corresponding dimnames of the array). It works fine if the array dimensions are > 1.
However, if I have 1x1x1 array, I cannot extract the slice as a matrix:
a <- array(1, c(1,1,1), list(A="a", B="b", C="c"))
a[1,,]
[1] 1
It is a scalar with no dimnames, hence part of the necessary information is missing. If I add drop=FALSE, I don't get a matrix but retain the original array:
a[1,,,drop=FALSE]
, , C = c
B
A b
a 1
The dimnames are here but it is still 3-dimensional. Is there an easy way to get a matrix slice from 1x1x1 array that would look like the above, just without the third dimension:
B
A b
a 1
I suspect the issue is that when indexing an array, we cannot distinguish between 'take 1 value' and 'take all values' in case where 'all' is just a singleton...
The drop parameter of [ is all-or-nothing, but the abind package has an adrop function which will let you choose which dimension you want to drop:
abind::adrop(a, drop = 3)
## B
## A b
## a 1
Without any extra packages, the best I could do was to apply and return the sub-array:
apply(a, 1:2, identity)
# or
apply(a, 1:2, I)
# B
#A b
# a 1

How to create sub-arrays access the i-th dimension of an array within for()?

In a for-loop, I run in i over an array which I would like to sub-index in dimension i. How can this be done? So a minimal example would be
(A <- array(1:24, dim = 2:4))
A[2,,] # i=1
A[,1,] # i=2
A[,,3] # i=3
where I index 'by foot'. I tried something along the lines of this but wasn't successful. Of course one could could create "2,," as a string and then eval & parse the code, but that's ugly. Also, inside the for loop (over i), I could use aperm() to permute the array such that the new first dimension is the former ith, so that I can simply access the first component. But that's kind of ugly too and requires to permute the array back. Any ideas how to do it more R-like/elegantly?
The actual problem is for a multi-dimensional table() object, but I think the idea will remain the same.
Update
I accepted Rick's answer. I just present it with a for loop and simplified it further:
subindex <- c(2,1,3) # in the ith dimension, we would like to subindex by subindex[i]
for(i in seq_along(dim(A))) {
args <- list(1:2, 1:3, 1:4)
args[i] <- subindex[i]
print(do.call("[", c(list(A), args)))
}
#Build a multidimensional array
A <- array(1:24, dim = 2:4)
# Select a sub-array
indexNumber = 2
indexSelection = 1
# Build a parameter list indexing all the elements of A
parameters <- list(A, 1:2, 1:3, 1:4)
# Modify the appropriate list element to a single value
parameters[1 + indexNumber] <- indexSelection
# select the desired subarray
do.call("[", parameters)
# Now for something completely different!
#Build a multidimensional array
A <- array(1:24, dim = 2:4)
# Select a sub-array
indexNumber = 2
indexSelection = 1
reduced <- A[slice.index(A, indexNumber) == indexSelection]
dim(reduced) <- dim(A)[-indexNumber]
# Also works on the left-side
A[slice.index(A, 2)==2] <- -1:-8

Extract array dimensions in Julia

Given a vector A defined in Matlab by:
A = [ 0
0
1
0
0 ];
we can extract its dimensions using:
size(A);
Apparently, we can achieve the same things in Julia using:
size(A)
Just that in Matlab we are able to extract the dimensions in a vector, by using:
[n, m] = size(A);
irrespective to the fact whether A is one or two-dimensional, while in Julia A, size (A) will return only one dimension if A has only one dimension.
How can I do the same thing as in Matlab in Julia, namely, extracting the dimension of A, if A is a vector, in a vector [n m]. Please, take into account that the dimensions of A might vary, i.e. it could have sometimes 1 and sometimes 2 dimensions.
A = zeros(3,5)
sz = size(A)
returns a tuple (3,5). You can refer to specific elements like sz[1]. Alternatively,
m,n = size(A,1), size(A,2)
This works even if A is a column vector (i.e., one-dimensional), returning a value of 1 for n.
This will achieve what you're expecting:
n, m = size(A); #or
(n, m) = size(A);
If size(A) is a one dimensional Tuple, m will not be assigned, while n will receive length(A). Just be sure to catch that error, otherwise your code may stop if running from a script.

How do concatenation and indexing differ for cells and arrays in MATLAB?

I am a little confused about the usage of cells and arrays in MATLAB and would like some clarification on a few points. Here are my observations:
An array can dynamically adjust its own memory to allow for a dynamic number of elements, while cells seem to not act in the same way:
a=[]; a=[a 1]; b={}; b={b 1};
Several elements can be retrieved from cells, but it doesn't seem like they can be from arrays:
a={'1' '2'}; figure; plot(...); hold on; plot(...); legend(a{1:2});
b=['1' '2']; figure; plot(...); hold on; plot(...); legend(b(1:2));
%# b(1:2) is an array, not its elements, so it is wrong with legend.
Are these correct? What are some other different usages between cells and array?
Cell arrays can be a little tricky since you can use the [], (), and {} syntaxes in various ways for creating, concatenating, and indexing them, although they each do different things. Addressing your two points:
To grow a cell array, you can use one of the following syntaxes:
b = [b {1}]; % Make a cell with 1 in it, and append it to the existing
% cell array b using []
b = {b{:} 1}; % Get the contents of the cell array as a comma-separated
% list, then regroup them into a cell array along with a
% new value 1
b{end+1} = 1; % Append a new cell to the end of b using {}
b(end+1) = {1}; % Append a new cell to the end of b using ()
When you index a cell array with (), it returns a subset of cells in a cell array. When you index a cell array with {}, it returns a comma-separated list of the cell contents. For example:
b = {1 2 3 4 5}; % A 1-by-5 cell array
c = b(2:4); % A 1-by-3 cell array, equivalent to {2 3 4}
d = [b{2:4}]; % A 1-by-3 numeric array, equivalent to [2 3 4]
For d, the {} syntax extracts the contents of cells 2, 3, and 4 as a comma-separated list, then uses [] to collect these values into a numeric array. Therefore, b{2:4} is equivalent to writing b{2}, b{3}, b{4}, or 2, 3, 4.
With respect to your call to legend, the syntax legend(a{1:2}) is equivalent to legend(a{1}, a{2}), or legend('1', '2'). Thus two arguments (two separate characters) are passed to legend. The syntax legend(b(1:2)) passes a single argument, which is a 1-by-2 string '12'.
Every cell array is an array! From this answer:
[] is an array-related operator. An array can be of any type - array of numbers, char array (string), struct array or cell array. All elements in an array must be of the same type!
Example: [1,2,3,4]
{} is a type. Imagine you want to put items of different type into an array - a number and a string. This is possible with a trick - first put each item into a container {} and then make an array with these containers - cell array.
Example: [{1},{'Hallo'}] with shorthand notation {1, 'Hallo'}

Resources