why exist a difference between appending lists and vectors? - r

My question is why the following code
list1 <- list()
list1[[1]] <- c()
list1[[1]] <- c(list1[[1]], 7)
shows the error
Error in list1[[1]] : subscript out of bounds
and why the following code
vector1 <- c()
vector1 <- c(vector1, 7)
works? I want to do something like this
for (i in c(1,2,3)){
for (j in c(1,2,3)){
list1[[i]].append(list3[[i]], j)
}
}

Are you looking for something like that ?
Using for loop
You can append numbers to each vector of a list by doing this:
list1 = vector("list",3)
for(i in 1:3)
{
for(j in 1:3)
{
list1[[i]] = c(list1[[i]],j)
}
}
And you get the following output:
> list1
[[1]]
[1] 1 2 3
[[2]]
[1] 1 2 3
[[3]]
[1] 1 2 3
Using lapply
You can do the same thing without the need to use for loop but instead lapply
list3 = vector("list",3)
list3 = lapply(list3,function(x){1:3})
and you get a similar output

Related

Dynamically appending n objects in a list

I am working in R.
I have n objects all named x followed by a number j = 1,..., n.
eg, for n = 5:
x1, x2, x3, x4, x5
I want to be able to list them all together dynamically depending on the n value:
list(x1,x2,x3,x4,x5)
In other words, I need to write a function that returns a list of those similarly-named objects automatically recognizing at what value of n to stop.
I tried this:
l <- vector()
for (k in (1:n)){
if (k != n){
u <- paste0("x",k, ",")
} else {
u <- paste0("x",k)
}
l <- append(l,u)
}
But obviously returns a list of characters...
Does anyone have an idea of how to do that?
Many thanks for your help.
mget gets a list of objects from their names. Construct the names using paste (vectorized), give it to mget (also vectorized) and you have your list:
l <- mget(paste0("x", 1:n))
I'd suggest trying to use lists from the start, rather than creating a bunch of objects then gathering them into a list. My answer at How to make a list of data frames has examples and discussion about this.
If you want to write a function:
> x1 <- 1:2
> x2 <- 1:3
> x3 <- 2:5
>
> make_list <- function(n){
+ l <- list()
+ for(i in 1:n){
+ l[[i]] <- get(paste0('x',i))
+ }
+ l
+ }
> make_list(3)
[[1]]
[1] 1 2
[[2]]
[1] 1 2 3
[[3]]
[1] 2 3 4 5
> make_list(1)
[[1]]
[1] 1 2
>

How to get the result in every round in a for loop in R

I want to have the indices for every "1" on a row of a matrix. However, when I coded as the followings, only the result for the last row outputs. How can I fix the problem and what is wrong with my code?
adjacency <- function(x) {
num_row <- nrow(x)
for (i in num_row){
output <- which (x[i,]==1)
print(output)
}
result <- list (output)
print(result)
}
A <- matrix(c(NA,1,0,1,1,NA,1,0,0,1,NA,1,1,0,1,NA),nrow=4)
A
adjacency(A)
You were only iterating over a single value, the number of rows in your matrix, and not over each row:
adjacency <- function(x) {
num_row <- nrow(x)
result<-list()
for (i in 1:num_row){
result[[i]] <- which (x[i,]==1)
}
print(result)
}
A <- matrix(c(NA,1,0,1,1,NA,1,0,0,1,NA,1,1,0,1,NA),nrow=4)
A
adjacency(A)
[[1]]
[1] 2 4
[[2]]
[1] 1 3
[[3]]
[1] 2 4
[[4]]
[1] 1 3

Use paste0 to create multiple object names with a for loop

I would like to create multiple object names with a for loop. I have tried the following which fails horribly:
somevar_1 = c(1,2,3)
somevar_2 = c(4,5,6)
somevar_3 = c(7,8,9)
for (n in length(1:3)) {
x <- as.name(paste0("somevar_",[i]))
x[2]
}
The desired result is x being somevar_1, somevar_2, somevar_3 for the respective iterations, and x[2] being 2, 5 and 8 respectively.
How should I do this?
somevar_1 = c(1,2,3)
somevar_2 = c(4,5,6)
somevar_3 = c(7,8,9)
for (n in 1:3) {
x <- get(paste0("somevar_", n))
print(x[2])
}
Result
[1] 2
[1] 5
[1] 8
We can use mget to get all the required objects in a list and use sapply to subset 2nd element from each of them.
sapply(mget(paste0("somevar_", 1:3)), `[`, 2)
#somevar_1 somevar_2 somevar_3
# 2 5 8

Matching in list of vectors with differents lengths

I have two lists like that :
List1 <- list(c("toto", "titi"), c("tata"), c("toto", "tz", "tutu"))
List2 <- list(c("titi", "toto", "tutu"),
c("tata", "trtr", "to", "tututu"),
c("to", "titi", "tutu", "tyty"),
c("titi", "tu", "tyty", "tete"),
c("tktk", "ta"))
And I want to build a list (of the matchings) which has a similar structure as the List1 object, except that the character vectors are replaced by a list of the matching indices of first level elements of List2, this for each string of each character vector.
The matching list that I would to obtain with list1 and list2 examples is thus :
Matchings <- list(list(list(1), list(1,3,4)),
list(list(2)),
list(list(1), list(), list(1,3)))
I've built the following code solution (that works, but too slow) with loops :
Matching_list <- lapply(List1, function(x) sapply(x, function(y) return(list())))
for (i in 1:length(List1)) {
for (j in 1: length(List1[[i]])) {
Matchings = list()
for (k in 1: length(List2)) {
if(any(List1[[i]][j] %in% List2[[k]])) {
Matchings <- c(Matchings, k)
}
if(length(Matchings) != 0) {
Matching_list[[i]][[j]] <- Matchings
}
}
}
}
... but it's definitly too slow for large lists. Thus, I seek for a solution that would make that stuff without loops as far as possible.
Could you help me?
How about this:
inds <- rep(seq_along(List2), sapply(List2, length))
#[1] 1 1 1 2 2 2 2 3 3 3 3 4 4 4 4 5 5
ls <- unlist(List2)
res <-
relist(sapply(unlist(List1), function(a) as.list(inds[which(ls %in% a)])), skeleton=List1)
all.equal(Matchings, res)
#[1] TRUE
Which will give your desired output. I doubt that its possible without, at least, looping over List1.

add a data frame to a constructed name

I have this
for(i in 1:10)
and within it, I have a data frame:
e.g.
df<-1:100
and I want to assign the dataframe to a specific name which I want to create
something like: (not that it works)
paste("name", variable[i])<- df
Edit:
How would I then go about accessing those constructed values in another loop (assuming i've used assign)
datalist <- paste("a",1:100,sep="")
for (i in 1:length(datalist)){
}
I suggest assign, as illustrated here:
for(i in 1:100){
df <- data.frame(x = rnorm(10),y = rpois(10,10))
assign(paste('df',i,sep=''),df)
}
You could store the output of your loop in a list:
set.seed(10)
x = list()
for(i in 1:10){
x[[i]] <- data.frame(x = rnorm(100), y = rnorm(100))
}
Then x will be a list of length 10 and each element of the list will be of dim c(100, 2)
> length(x)
[1] 10
> dim(x[[1]])
[1] 100 2
>
Of course you could name the elements of the list, as well:
names(x) = letters[1:10]
x[["a"]]
x y
1 0.01874617 -0.76180434
2 -0.18425254 0.41937541
3 -1.37133055 -1.03994336
4 -0.59916772 0.71157397
5 0.29454513 -0.63321301
6 0.38979430 0.56317466
...

Resources