Suppose if I want to have 10 element array each element is a list/map. I am doing this:
x = array(list(), 10)
x[1][[ "a" ]] = 1
Warning message:
In x[1][["a"]] = 1 :
number of items to replace is not a multiple of replacement length
>
Is this the right approach? I want each element of the array to be a map.
What you're calling an "array" is usually just called a list in R. You're getting tripped up by the difference between [ and [[ for lists. See the section "Recursive (list-like) objects" in help("[").
x[[1]][["a"]] <- 1
UPDATE:
Note that the solution above creates a list of named vectors. In other words, something like
x[[1]][["a"]] <- 1
x[[1]][["b"]] <- 1:2
won't work because you can't assign multiple values to one element of a vector. If you want to be able to assign a vector to a name, you can use a list of lists.
x[[1]] <- as.list(x[[1]])
x[[1]][["b"]] <- 1:2
If you really want to do this, then, because the elements of the lists in each element of the array do not have names, you can't index by a character vector. In your example, there is no x[1][[ "a" ]]:
> x[1][[ "a" ]]
NULL
If there are no names then you need to index by a numeric:
> x[1][[ 1 ]] <- 1
[1] 1
It would seem more logical to have a list though than an array:
> y <- vector(mode = "list", length = 10)
> y
[[1]]
NULL
[[2]]
NULL
[[3]]
NULL
[[4]]
NULL
[[5]]
NULL
....
Related
I have a very long Array (1955x2417x1) in R where each position stores a list of two vector (named "max" and "min") of length 5.
I would like to find a simple way to create a multidimensional array (dim 1955x2417x5) where each position holds a single value from vector "max"
I have looked at answers such as array of lists in r
but so far without success.
I know I can access the list in each position of the array using
myarray[posX, PosY][[1]][["max"]]
but how to apply that to the whole Array?
SO far I have tried
newArray <- array( unlist(myarray[][[1]][["max"]]), c(1955, 2417, 5))
and
NewArray <-parApply(cl, myarray, c(1:2), function(x) {
a=x[[1]][["max"]]
} )
but the results are not right.
Do you have any suggestion?
Let
e <- list(min = 1:3, max = 4:6)
arr <- array(list(e)[rep(1, 8)], c(2, 4))
dim(arr)
# [1] 2 4
Then one option is
res <- apply(arr, 1:2, function(x) x[[1]][["max"]])
dim(res)
# [1] 3 2 4
and, if the order of dimensions matters,
dim(aperm(res, c(2, 3, 1)))
# [1] 3 2 4
I have a function that takes one vector as its input, uses another function to create a derivative vector from the input, and then compares the two vectors to produce its output vector. I currently have it working with a for loop as follows:
The original array, nameVec, is used as the input to the following functions:
% INPUT: nameVec = '' 'a' 'b' 'aa' 'ab' 'ba' 'aba' 'abb'
First, a function called computeParentName removes the last character from each array element of nameVec and produces this cell array:
% OUTPUT: parentNameVec = '' '' '' 'a' 'a' 'b' 'ab' 'ab
Next, the function computeParentIndex finds the indices of where each element in parentNameVec appears in nameVec:
function [parentIndexVec] = computeParentIndex(nameVec)
parentNameVec = computeParentName(nameVec);
[~,parentIndexVec] = ismember(parentNameVec, nameVec);
end
% OUTPUT: parentIndexVec = 1 1 1 2 2 3 5 5
I am now trying to develop a function that essentially acts in reverse, as it takes nameVec and outputs a cell array, which contains at each index, an array of all indices in parentNameVec where the value is that of the output array's ('daughterIndexVec`) current index
function [daughterIndexVec] = computeDaughterIndex(nameVec)
parentIndexVec = computeParentIndex(nameVec);
for i=1:length(parentIndexVec)
daughterIndexVec{i} = find(parentIndexVec==i);
end
end
% OUTPUT: daughterIndexVec = {[1,2,3] [4,5] [6] [] [7,8] [] [] []}
Is there a simpler (more efficient) way to accomplish this without use of for loops?
Any assistance is greatly appreciated!
You can use the second output of ismember to get the locations of each value in parentNameVec in nameVec and then use accumarray to group all indices which share the same index in nameVec together in a cell array.
[~, ind] = ismember(parentNameVec, nameVec);
daughterIndexVec = accumarray(ind(:), 1:numel(ind), [numel(ind) 1], #(x){x.'});
% {[1,2,3] [4,5] [6] [] [7,8] [] [] []}
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
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
I just found myself in a position where I have two arrays in Tcl.
I'm given $W_Array and $P_Array.
I need to traverse through one array not knowing what the size of each one is before hand, and execute a command only when there is a value for both arrays. Yes the array lengths could be different.
What is the best way of doing this?
The other answers jumped to using lists, I presume you mean Tcl's array, which are also called hash maps or associative arrays.
I think you're asking for something like:
array set a1 {a 1 b 2 c 3 d 4 e 5}
array set a2 {z 0 x 1 b 2 e 99}
foreach n [array names a1] {
if {[info exists a2($n)]} {
puts "Do something with $a1($n) and $a2($n)"
}
}
# FOREACH LOOP RESULTS IN THESE TWO PRINTOUTS
Do something with 5 and 99
Do something with 2 and 2
Not sure exactly what you mean by "a value for both arrays", but tcl's foreach supports iteration over multiple arrays at once... so you can say e.g.
foreach w $W_Array p $P_Array {
if {$w == $val && $p == $val} {
...
}
}
When the arrays are not of the same length, foreach will return all values from the longest array and the empty value {} for the missing elements in any shorter arrays.
Use llength command to find out if the arrays contain a value.
if {[llength $W_Array] > 0 && [llength $P_Array] > 0} {
# Do something
}