Dynamically appending n objects in a list - r

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
>

Related

Creating a 3 by 1 matrix from three columns in a data frame and multiplying by a 2*3 in the correct order and applying to all the rows

I have a 23 constant complex matrix and create a 31 matric created from 3 columns of a data frame(this should be done for each row) and the result is going to be a 2*1 matric called N. This should be applied to all of the rows so I define a while loop. Then N[1,1] and N[2,1] are used to calculate the final thing, but I am not getting the result I want, I calculated Q from each row!!! I put Q like Q[i] inside the loop and still not the result I wanted.
library(dplyr)
library(tidyr)
library(readxl)
library(Matrix)
library(matlib)
library(readxl)
library(MASS)
c1 <- c(2+3i,1+2i,3+4i)
c2 <- c(1+4i,4+6i,7+1i)
c3 <- c(4+5i,2+2i,3+4i)
c4=2
df <- data.frame(c1,c2,c3)
print(df)
a1 <- matrix(c(1+2i,2+4i,5+1i,1+2i,5+4i,2+2i),nrow=3,ncol=2, byrow=T)
a_inv <- ginv(a1)
print(a_inv)
i <-1
while(i <= nrow(df)){
C <- matrix(c(df$c1[1],df$c2[1],df$c3[1]), nrow=3, ncol=1)
N <- a_inv %*% C
N1 <- N[1,1]
N2 <- N[2,1]
i=i+1
}
Q <-((N1+N2)*c4)
print(Q)
I would make a couple of empty lists to receive the while loop iteration results, made outside the loop:
N <- list()
lst_31_2 <- list() # your C
i = 1
while (i <= nrow(df)) {
lst_31_2[[i]] = matrix(c(df$c1[i], df$c2[i], df$c3[i]), nrow=3, ncol=1)
N[[i]] = a_inv %*% lst_31_2[[i]]
i= i+1
}
> str(N)
List of 3
$ : cplx [1:2, 1] 0.386+0.338i 0.781-0.169i
$ : cplx [1:2, 1] 0.393+0.602i 0.413-0.568i
$ : cplx [1:2, 1] 0.81+0.157i 0.452-0.351i
Then using the N values, a for loop:
Q <- list()
for (j in 1:nrow(df)) {
+ Q[[j]] <- (N[[j]][1,1] + N[[j]][2,1]) * c4
+ }
Q
[[1]]
[1] 2.333981+0.337864i
[[2]]
[1] 1.61165+0.067961i
[[3]]
[1] 2.524272-0.38835i
# or
unlist(Q)
[1] 2.333981+0.337864i 1.611650+0.067961i 2.524272-0.388350i
> unlist(Q)[1]
[1] 2.333981+0.337864i
> unlist(Q)[2]
[1] 1.61165+0.067961i
> unlist(Q)[3]
[1] 2.524272-0.38835i
Note the [[ to extract list values and [ for matrix. And I'll still say my best guess as I don't know what the expected value should be. The above 'while' could also be a for loop, which would simplify to one loop, this assuming df and a_inv in environment and C and Q lists:
for(k in 1:nrow(df)) {
lst_31_2[[k]] = matrix(c(df$c1[k], df$c2[k], df$c3[k]), nrow=3, ncol=1)
N[[k]] = a_inv %*% lst_31_2[[k]]
Q[[k]] <- (N[[k]][1,1] + N[[k]][2,1]) * c4
df$Q[k] <- Q[[k]]
}
> df
c1 c2 c3 Q
1 2+3i 1+4i 4+5i 2.333981+0.337864i
2 1+2i 4+6i 2+2i 1.611650+0.067961i
3 3+4i 7+1i 3+4i 2.524272-0.388350i
> Q
[[1]]
[1] 2.333981+0.337864i
[[2]]
[1] 1.61165+0.067961i
[[3]]
[1] 2.524272-0.38835i
ls()
[1] "a_inv" "a1" "c1" "c2" "c3" "c4"
[7] "df" "k" "lst_31_2" "N" "Q"
Because the objects were initialized as empty, outside the loop, they are all available after processing and can be removed rm(Q) if they are cluttering up your workspace.
And I find building the steps like this, getting each part returning reasonably expected numbers, then next, then combining easier to later debug errors in my logic. So I first try to do it in the simplest base way I can.

R assign along a vector

I have an ini-file, read as a list by R (in the example l). Now I want to add further sub-lists along a vector (m) and assign always the same constant to them. My attempt so far:
l <- list("A")
m <- letters[1:5]
n <- 5
for (i in 1:5){
assign(paste0("l$A$",m[i]), n)
}
# which does not work
# example of the desired outcome:
> l$A$e
[1] 5
I don't think that I have fully understood how lists work yet...
Try
L[["A"]][m] <- n
L$A$e
# [1] 5
Data:
L <- list(A = list())
m <- letters[1:5]
n <- 5

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

Sum of all vectors of variables with common prefix

Is it possible to sum all vector variables with a common prefix ?
Exemple:
x1 <- c(1,2,3)
x2 <- c(4,5,6)
.
.
.
xn <- c(n,n,n)
y = x1 + x2 + ... xn
The number of variables xn (ie with prefix x) is only known at runtime.
Assuming your y has the same dimension as x, you could try capturing all the variables into the list and apply a summation operation.
> x2 <- c(4,5,6)
> x1 <- c(1,2,3)
> ls(pattern = "^x\\d+$") # this is regex for finding "x" and "digits",
# ^ is start of string, $ is end of string
[1] "x1" "x2"
> sapply(ls(pattern = "^x\\d+$"), get, simplify = FALSE)
$x1
[1] 1 2 3
$x2
[1] 4 5 6
> out <- sapply(ls(pattern = "^x\\d+$"), get, simplify = FALSE)
> Reduce("+", out)
[1] 5 7 9
You can also use mget as suggested by #LyzandeR's, especially if fancy one-liners.
Reduce("+", mget(ls(pattern = "^x\\d+$")))
You can check an example:
xx <- 1
xx2 <- 2
xx3 <- 3
#get the names of the variables containing xx
vars <- ls(pattern = 'xx')
#mget will get the variables from the names, unlist will add them in an atomic vector
sum(unlist(mget(vars)))
#[1] 6
A very naive solution could be:
# first 2 vectors are of interest
x1 <- c(1,2,3)
x2 <- c(4,5,6)
# answer doesn't need to have z sum in it
z <- c(7,8,9)
# create a dummy answer vector, initialize it will all 0; length will be the length of single vector that we are adding
answer<-rep(0,length(x1))
# loop through each variable in current environment
for (var in ls()){
# see if variable name begins with x
if (startsWith(var,'x')){
# add it to our answer
answer = answer + get(var)
}
}
# print the answer
print(answer)

Adding elements to a list in for loop in R

I'm trying to add elements to a list in a for loop. How can I set the field name?
L <- list()
for(i in 1:N)
{
# Create object Ps...
string <- paste("element", i, sep="")
L$get(string) <- Ps
}
I want every element of the list to have the field name dependent from i (for example, the second element should have "element2")
How to do this? I think that my error is the usage of get
It seems like you're looking for a construct like the following:
N <- 3
x <- list()
for(i in 1:N) {
Ps <- i ## where i is whatever your Ps is
x[[paste0("element", i)]] <- Ps
}
x
# $element1
# [1] 1
#
# $element2
# [1] 2
#
# $element3
# [1] 3
Although, if you know N beforehand, then it is better practice and more efficient to allocate x and then fill it rather than adding to the existing list.
N <- 3
x <- vector("list", N)
for(i in 1:N) {
Ps <- i ## where i is whatever your Ps is
x[[i]] <- Ps
}
setNames(x, paste0("element", 1:N))
# $element1
# [1] 1
#
# $element2
# [1] 2
#
# $element3
# [1] 3

Resources