Get object and indices from subsetting call - r

Basically, I would like to create an R function separate_call that gets an argument like x[ind] and returns x and ind (so, from the parent environment):
x <- 1:10
ind <- 2:3
separate_call(x[ind]) ## should return `list(1:10, 2:3)`
I know that I need to use non-standard evaluation and some tree parsing but I'm not familiar enough with these two concepts. Any help would be appreciated.

Looking at the code of pryr:::tree and experimenting a little bit, I found a solution:
separate_call <- function(call) {
call.sep <- as.list(substitute(call))
parent_env <- parent.frame()
x <- eval(call.sep[[2]], parent_env)
ind <- eval(call.sep[[3]], parent_env)
list(x, ind)
}
Verification:
> x <- 1:10
> ind <- 2:3
> separate_call(x[ind])
[[1]]
[1] 1 2 3 4 5 6 7 8 9 10
[[2]]
[1] 2 3
> separate_call(x[1:2])
[[1]]
[1] 1 2 3 4 5 6 7 8 9 10
[[2]]
[1] 1 2

I am adding this solution, not very elegant, see if this fits your need.
separate_call <- function(m){
dprse <- deparse(substitute(m)) ##deparsing the data: to make it as string
lyst <- strsplit(dprse,"\\[|\\]")[[1]] ##removing the square brackets to sparate contents of m
lapply(lyst, function(y)eval(parse(text = y), envir = parent.frame()))
}
I hope this works, I tried it by calling it in three different ways
separate_call(1:10[ind])
separate_call(x[2:3])
separate_call(1:10[2:3])
They all gave me same response
> separate_call(1:10[ind])
[[1]]
[1] 1 2 3 4 5 6 7 8 9 10
[[2]]
[1] 2 3
> separate_call(x[2:3])
[[1]]
[1] 1 2 3 4 5 6 7 8 9 10
[[2]]
[1] 2 3
> separate_call(1:10[2:3])
[[1]]
[1] 1 2 3 4 5 6 7 8 9 10
[[2]]
[1] 2 3

Related

R: using assign() for list elements

Suppose I have an empty list grid. Is it possible to use assign() to assign several data frames to list elements?
grid <- list()
assign(grid[[1]],data.frame(x=1:4,y=5:8))
assign(grid[[2]],data.frame(x=2:4,y=6:8))
So that you would get an output like:
> grid
[[1]]
x y
1 5
2 6
3 7
4 8
[[2]]
x y
2 6
3 7
4 8
Code:
grid <- list()
type = "a"
for(k in 1:3){
assign(paste0("grid[[",k,"]]"),ifelse(type=="a",
data.frame(x=1:4,y=5:8),
data.frame(x=2:4,y=6:8)))
}
Desired output: (since type will always be "a")
> grid
[[1]]
x y
1 5
2 6
3 7
4 8
[[2]]
x y
1 5
2 6
3 7
4 8
[[3]]
x y
1 5
2 6
3 7
4 8
I may be missing something, but I don't see why you need to use assign() at all? Doesn't this do what you wanted?
grid <- list()
type = "a"
for(k in 1:3){
if(type=="a") grid[[k]] <- data.frame(x=1:4,y=5:8)
}
EDIT:
for(k in 1:3){
if(type=="a") grid[[k]] <- data.frame(x=1:4,y=5:8)
if(type=="b") grid[[k]] <- data.frame(x=2:4,y=6:8)
}

Recursive looping in r

I am new in R but I want to loop through elements of a given list recursively, to be presice I have alist of vectors where the first vector is given by (1,2,3,4), then I now want to loop through this vector and append the second vector obtained to the original list, again loop thorugh second vector in the list and get the third vector which is also appended on the original list and so on. I have this code to start with`
occlist <- list()
occ_cell <- c(1,2,3,4)
for(i in occ_cell){
occ_cell <- seq(i,4*i, by = 1)
occlist[[i]] <- occ_cell
}
`
gives the following list
#[[1]]
#[1] 1 2 3 4
#[[2]]
#[1] 2 3 4 5 6 7 8
#[[3]]
# [1] 3 4 5 6 7 8 9 10 11 12
#[[4]]
# [1] 4 5 6 7 8 9 10 11 12 13 14 15 16
I think to be more clear, lets have the following figure
recOcc <- function(i) {
if (i == 0) return ( NULL )
append( recOcc(i-1), list(seq(i, 4*i)) )
}
And, call with (to reproduce your output)
recOcc(4)
# [[1]]
# [1] 1 2 3 4
#
# [[2]]
# [1] 2 3 4 5 6 7 8
#
# [[3]]
# [1] 3 4 5 6 7 8 9 10 11 12
#
# [[4]]
# [1] 4 5 6 7 8 9 10 11 12 13 14 15 16
You can also use Recall to name your recursive function in the recursive call, which allows for the function name to change.
Edit
For the tree structure, you could try this
## i is the number to start the sequence
## depth determines how deep to recurse
recOcc2 <- function(i, depth=3, cur.depth=0) {
if (depth==cur.depth) return(seq(i, 4*i))
acc <- as.list(seq(i, 4*i))
for (ii in seq_along(acc))
acc[[ii]] <- recOcc2(acc[[ii]], depth, cur.depth+1)
acc
}
## To recreate the simple list
res <- recOcc2(1, depth=1)
## For nested lists
res <- recOcc2(1, depth=2)

Constant subset of a variable length list for some list[[x]] in R

Imagine the following data:
listA
[[1]]
[1] 1 2 3 4 5 6 7
[[2]]
[1] 1 2 3 4 5 6
[[3]]
[1] 1 2 3 4 5
How to select:
listA[[1:2]][1:4]
Using 1:2 there is not allowed, so is there any way to select these when it is known that this selection exists (both the 1:2 and 1:4 parts)?
What I would like returned:
listA
[[1]]
[1] 1 2 3 4
[[2]]
[1] 1 2 3 4
What about just using lapply,
R> l = list(A = 1:6, B=1:4, C = 1:5)
R> lapply(l[1:2], "[", 1:4)
$A
[1] 1 2 3 4
$B
[1] 1 2 3 4
You probably have to use lapply.
lapply(listA, function(x) x[1:4])
If your actual list is longer, you can access the first two elements of listA by listA[1:2]. So this should work:
lapply(listA[1:2], function(x) x[1:4])

Loop through a vector of vectors

When I loop through a vector of vectors, the result of each loop is several vectors. I would expect the result of each loop to be a vector. Please see the following example:
foo <- seq(from=1, to=5, by=1)
bar <- seq(from=6, to=10, by=1)
baz <- seq(from=11, to=15, by=1)
vects <- c(foo,bar,baz)
for(v in vects) {print(v)}
# [1] 1
# [1] 2
# [1] 3
# [1] 4
# [1] 5
# [1] 6
# [1] 7
# [1] 8
# [1] 9
# [1] 10
# [1] 11
# [1] 12
# [1] 13
# [1] 14
# [1] 15
This is odd as I would expect three vectors given it (should) iterate three times given the vector, c(foo,bar,baz). Something like:
# [1] 1 2 3 4 5
# [1] 6 7 8 9 10
# [1] 11 12 13 14 15
Can anyone explain why I am getting this result (15 vectors) and how to achieve the result I am looking for (3 vectors)?
Look at what vects is:
> vects
[1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
The c() joins (in this case) the three vectors, concatenating them into a single vector. In the for() loop, v takes on each values in vects in turn and prints it, hence the result you see.
Did you want a list of the three separate vectors? If so
> vects2 <- list(foo, bar, baz)
> for(v in vects2) {print(v)}
[1] 1 2 3 4 5
[1] 6 7 8 9 10
[1] 11 12 13 14 15
In other words, form a list of the vectors, not a combination of the vectors.
Substitute vects <- list(foo,bar,baz) for vects <- c(foo,bar,baz).
There is no such thing (really) as a vector of vectors.

How to output the data with different lengths

R Version 2.11.1 32-bit on Windows 7
I'm wondering if anyone else has encountered this question. I got several arrays with different lengths, and I want put them together to output. For example:
a=c(1,2,3);
b=c(2,4,1,6)
c=c(4,5,9,2,8)
ra=rank(a);#ra=1 2 3
rb=rank(b);#rb=2 3 1 4
rc=rank(c);#rc=2 3 5 1 4
then how to put ra, rb and rc together to be this:
1 2 3
2 3 1 4
2 3 5 1 4
Yes, list() may be help, but how could I save it to my PC.
I tred to use write.table(), but fail.
Transform list to matrix of strings.
a=c(1,2,3);
b=c(2,4,1,6)
c=c(4,5,9,2,8)
rlist <- lapply(list(a,b,c), rank)
m <- do.call(rbind, lapply(rlist,
function(x) paste(x,collapse=" ")
)
)
write.table(m,file="file_name")
Sounds like you want a list.
> list(ra, rb, rc)
[[1]]
[1] 1 2 3
[[2]]
[1] 2 3 1 4
[[3]]
[1] 2 3 5 1 4
> rlist <- lapply( list(a,b,c), rank)
> rlist
[[1]]
[1] 1 2 3
[[2]]
[1] 2 3 1 4
[[3]]
[1] 2 3 5 1 4

Resources