I'm trying to write a function that maps a function to reduce to concatenate a list of vectors together into 1 with the very first entry and the very last entry.
For example,
reduce(list(1:10, 11:20, 21:100), r_cat, .init = NULL)
should return a vector equal to
1:100
This is what I have so far.
r_cat = function(x, y) {
out <- y[[1]]
for(i in seq(2, length(y))) {
out <- x(out, y[[i]])
}
out
}
Any thoughts?
No need to write a new function, unlist solves your problem:
List <- list(1:10, 11:20, 21:100)
unlist(List)
If you want to use Reduce from R base, then you can use c
Reduce("c", List)
You can also get the same result plugging c into reduce from purrr
library(purrr)
reduce(List, c)
Related
a<-c(0,1,1,0)
b<-c(1,0,0,0)
c<-c(0,0,0,1)
binary_subset<-function(a){
a_seq = lapply(a, seq, 0) # keep 0s as 0, make 1s c(1, 0)
subset=do.call(expand.grid, a_seq)
colnames(subset)=(1:length(a))
return(subset)
}
test_fun<-function(a,b,c,d){
list <- list(a,b,c,d)
interactions_abc<-do.call("rbind",lapply(list, binary_subset))
interactions_no_duplicate<-unique(interactions_abc[1:length(a)])
rownames(interactions_no_duplicate)=1:nrow(interactions_no_duplicate)
interactions_no_duplicate
}
>test_fun(a,b,c,d)
Error in test_fun(a, b, c, d) : object 'd' not found
I am trying to write a function where the input is not fixed. I have defined the function for 4 binary vectors. If I input 3 binary vectors, I am getting an error because the 4th vector is missing. This will work only if I input 4 binary vectors.
How can I fix this? Means: if I input 2 or 3 vectors, the function will produce the corresponding output; that means the function will run for two vectors and ignore the rest.
Maybe you can use ... for the function arguments, e.g.,
test_fun <- function(...) {
list <- list(...)
interactions_abc <- do.call("rbind", lapply(list, binary_subset))
interactions_no_duplicate <- unique(interactions_abc[1:length(list[[1]])])
rownames(interactions_no_duplicate) <- 1:nrow(interactions_no_duplicate)
interactions_no_duplicate
}
Consider passing in a list as single, sole argument by retrieving all numeric vectors from global environment with eapply and Filter. Below functions are re-factored for one line where { and } are optional.
a <- c(0,1,1,0)
b <- c(1,0,0,0)
c <- c(0,0,0,1)
binary_subset <- function(x) {
setNames(do.call(expand.grid, lapply(x, seq, 0)), 1:length(a))
}
test_fun <- function(mylist) {
data.frame(unique(do.call("rbind", lapply(mylist, binary_subset))),
row.names = NULL, check.names = FALSE)
}
vecs <- Filter(is.numeric, eapply(.GlobalEnv, identity))
test_fun(vecs)
Online Demo
I have following code which I perform with for loop to generate a 3D array "newarr".
n1<-c(1,2,3,4,5)
n2<-c(3,4,5,6,7)
n3<- c(4,5,6,7,8)
afun <- function(y,p,q,r){
calc=1/(1+(((y-p)/q)^(2*r)))
return(calc)
}
newarr<- array(dim = c(4,5,5))
Amat<-matrix(data=c(1:10,NA,NA,NA,NA,15:20),nrow = 4,ncol = 5)
Bmat<-matrix(data=c(1:6,NA,NA,NA,NA,11:20),nrow = 4,ncol = 5)
Qmat<- +(!is.na(Amat) & !is.na(Bmat))
for(i in 1:5){
res<-afun(Amat,n1[i],n2[i],n3[i])
newarr[,,i]<- res
}
I want to use Mapply (or any apply function) instead of for loop.
arr2 <- array((mapply(function(x,y,n1,n2,n3) if(x==1) afun(y,n1,n2,n3) else 0,Qmat,Amat,n1,n2,n3)),c(4,5,5))
The following code seems to help but without condition as described further:
newarr <- array(mapply(afun, n1,n2,n3, MoreArgs = list(y=Amat)), c(4,5,5))
I want to include a condition by using Qmat (a 4x5 matrix with 0 and 1), so that when '0' is observed, no operation should be performed and return '0'value to fill matrix. For 1s in Qmat, perform 'afun' function and return the value to "newarr" to form a 3D matrix.
Thanks for the help!!
This will give you the desired result:
newarr <- array(mapply(afun, n1,n2,n3, MoreArgs = list(y=Amat)), c(4,5,5))
this is using the implicit SIMPLIFY=TRUE of mapply(). With SIMPLIFY=TRUE each result is reduced to a vector. (a matrix is a vector with a dimension attribute)
Another variant is
array(unlist(mapply(afun, n1,n2,n3, MoreArgs = list(y=Amat), SIMPLIFY = FALSE)), c(4,5,5))
here you will get a list of matrices as result from mapply(). You have to unlist.
my_list = list()
my_list[[1]] = c("Fast","Slow","Heavy","Light")
my_list[[2]] = c("Fast","Small","Intelligent","Light")
my_list[[3]] = c("Dumb","Slow","Heavy","Light")
my_list[[4]] = c("Slow","Intelligent","Dumb","Heavy")
my_list[[5]] = c("Heavy","Light","Intelligent","Tall")
This is a simplified version of what I am trying to do, but how can I filter a list so that if two strings are contained within it (ie. Fast and Slow, Tall and Small, Heavy and Light, lastly, Intelligent and Dumb), then they can are removed to leave a final vector with sensible vectors.
I have been trying to do this with an IF function, is that the most appropriate way?
This would be what you want:
cont_check <- function(x) {
cont_words <- list(c("Fast", "Slow"),
c("Heavy", "Light"))
found <- sum(sapply(cont_words, function (y) sum(y %in% x) == 2)) > 0
return(found)
}
sapply(my_list, cont_check)
# select ones
# my_list[!sapply(my_list, cont_check)]
Suppose I have a list of functions and a vector of parameter values:
functions <- list(a = function(x) x *2, b = function(x) x*3, c = function(x) x * 4)
paramVector <- c(2, 2, 1)
Now I want the following functionality of calling each function with the corresponding parameter and collating the result into a vector:
result <- c()
for (idx in 1:length(functions)) {
result[idx] <- functions[[idx]](paramVector[idx])
}
result
Is there a way to do this without the for loop?
To iterate over the functions and paramVector objects at the same time, use Map. For example
Map(function(f,p) f(p), functions, paramVector)
Note that Map() always returns a list. You can also use mapply() which will attempt to simplify to a vector
mapply(function(f,p) f(p), functions, paramVector)
I would like to use a function from the apply family (in R) to apply a function of two arguments to two matrices. I assume this is possible. Am I correct? Otherwise, it would seem that I have to put the two matrices into one, and redefine my function in terms of the new matrix.
Here's an example of what I'd like to do:
a <- matrix(1:6,nrow = 3,ncol = 2)
b <- matrix(7:12,nrow = 3,ncol = 2)
foo <- function(vec1,vec2){
d <- sample(vec1,1)
f <- sample(vec2,1)
result <- c(d,f)
return(result)
}
I would like to apply foo to a and b.
(Strictly answering the question, not pointing you to a better approach for you particular use here....)
mapply is the function from the *apply family of functions for applying a function while looping through multiple arguments.
So what you want to do here is turn each of your matrices into a list of vectors that hold its rows or columns (you did not specify). There are many ways to do that, I like to use the following function:
split.array.along <- function(X, MARGIN) {
require(abind)
lapply(seq_len(dim(X)[MARGIN]), asub, x = X, dims = MARGIN)
}
Then all you have to do is run:
mapply(foo, split.array.along(a, 1),
split.array.along(b, 1))
Like sapply, mapply tries to put your output into an array if possible. If instead you prefer the output to be a list, add SIMPLIFY = FALSE to the mapply call, or equivalently, use the Map function:
Map(foo, split.array.along(a, 1),
split.array.along(b, 1))
You could adjust foo to take one argument (a single matrix), and use apply in the function body.
Then you can use lapply on foo to sample from each column of each matrix.
> a <- matrix(1:6,nrow = 3,ncol = 2)
> b <- matrix(7:12,nrow = 3,ncol = 2)
> foo <- function(x){
apply(x, 2, function(z) sample(z, 1))
}
> lapply(list(a, b), foo)
## [[1]]
## [1] 1 6
## [[2]]
## [1] 8 12