Sum of all vectors of variables with common prefix - r

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)

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
>

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

Split a vector into multiple vectors in R

I want to split one vector(x) into multiple vectors(x1, x2 ,... , xn).
My input: x <- 1:10
My desire output:
x1 <- c(1,2,3,4)
x2 <- c(2,3,4,5)
x3 <- c(3,4,5,6)
x4 <- c(4,5,6,7)
x5 <- c(5,6,7,8)
x6 <- c(6,7,8,9)
x7 <- c(7,8,9,10)
My code(thanks to Mrs.Richard Herron for inspiration):
x <- 1:10
n <-3
vectors <- function(x, n) split(x, sort(rank(x) %% n))
vectors(x,n)
Thanks very much!
We can use lapply to loop over the sequence of 'x' such that we have a length of 4 in each of the elements in list, create a sequence (:) from that index to index + n, subset the 'x'. If needed to have individual vectors, we set the names of the list and use list2env.
n <- 3
lst <- lapply(1:(length(x)-n), function(i) x[i:(i+n)])
names(lst) <- paste0("x", seq_along(lst))
list2env(lst, envir = .GlobalEnv)
x1
#[1] 1 2 3 4
x2
#[1] 2 3 4 5
x3
#[1] 3 4 5 6
Or we can also create a matrix instead of multiple vectors in the global environment where each row corresponds to the vector of interest
matrix(x[1:4] + rep(0:6, each = 4), ncol=4, byrow = TRUE)

Turning a couple of vectors into a list of vectors

Suppose I have a collection of independent vectors, of the same length. For example,
x <- 1:10
y <- rep(NA, 10)
and I wish to turn them into a list whose length is that common length (10 in the given example), in which each element is a vector whose length is the number of independent vectors that were given. In my example, assuming output is the output object, I'd expect
> str(output)
List of 10
$ : num [1:2] 1 NA
...
> output
[[1]]
[1] 1 NA
...
What's the common method of doing that?
use mapply and c:
mapply(c, x, y, SIMPLIFY=FALSE)
[[1]]
[1] 1 NA
[[2]]
[1] 2 NA
..<cropped>..
[[10]]
[1] 10 NA
Another option:
split(cbind(x, y), seq(length(x)))
or even:
split(c(x, y), seq(length(x)))
or even (assuming x has no duplicate values as in your example):
split(c(x, y), x)
Here is a solution that allows you to zip arbitrary number of equi-length vectors into a list, based on position of the element
merge_by_pos <- function(...){
dotlist = list(...)
lapply(seq_along(dotlist), function(i){
Reduce('c', lapply(dotlist, '[[', i))
})
}
x <- 1:10
y <- rep(NA, 10)
z <- 21:30
merge_by_pos(x, y, z)

Evaluate a symbolic Ryacas expression

This is a reproducible example:
a <- 0.05
za.2 <- qnorm(1-a/2)
b <- 0.20
zb <- qnorm(1-b)
lambda12 <- -log(1/2)/12
lambda18 <- -log(1/2)/18
theta <- lambda18/lambda12
(d = round(4*(za.2+zb)^2/log(theta)^2))
Tf<-36
library(Ryacas)
n <- Sym("n")
Solve(n/2*(2-exp(-lambda12*Tf)-exp(-lambda18*Tf))==d , n)
The last line returns
expression(list(n == 382/1.625))
Is there a way to extract the quotient and assign it to another variable (235.0769)?
G.Grothendieck pointed out in comments that you'll need to first to capture the expression to be operated upon below:
soln <- Solve(n/2*(2-exp(-lambda12*Tf)-exp(-lambda18*Tf))==d , n)
X <- yacas(soln)$text
Then, to extract the quotient, you can take advantage of the fact that many R language objects either are or can be coerced to lists.
X <- expression(list(n == 382/1.625))
res <- eval(X[[1]][[2]][[3]])
res
[1] 235.0769
The following just shows why that sequence of indices extracts the right piece of the expression:
as.list(X)
# [[1]]
# list(n == 382/1.625)
as.list(X[[1]])
# [[1]]
# list
#
# [[2]]
# n == 382/1.625
as.list(X[[1]][[2]])
# [[1]]
# `==`
#
# [[2]]
# n
#
# [[3]]
# 382/1.625

Resources