Imagine I have this bit of nested for loop, which prints all combinations of a and b
a = c(1,2,3,4)
b = c(2,3,4,5)
for(i in a){
for(k in b){
print(i + k)
}}
So the output looks like this
[1] 3
[1] 4
[1] 5
[1] 6
[1] 4
[1] 5
[1] 6
[1] 7
[1] 5
[1] 6
[1] 7
[1] 8
[1] 6
[1] 7
[1] 8
[1] 9
How do I loop through the two loops to get a result with only 4 items, the sum of elements from a and b with the same index, akin to looping through a dictionary in Python? I would like to have result like this:
[1] 3
[1] 5
[1] 7
[1] 9
or this
[1] 3 5 7 9
Whereby I simply add up a and b like adding up two columns in a dataframe to produce a third of the same length.
I appreciate any help.
Try mapply:
mapply(`+`, a, b)
# [1] 3 5 7 9
We can replace + any other function, for example paste or *:
mapply(paste, a, b)
# [1] "1 2" "2 3" "3 4" "4 5"
mapply(`*`, a, b)
# [1] 2 6 12 20
In R, loops are wrapped into *apply functions, see:
Grouping functions (tapply, by, aggregate) and the *apply family
As pointed out in the comments, in R, mathematical operators such as + are Vectorized. This means that by default you can feed them vectors as arguments and they will know how to walk through the elements in each input vector. Therefore simply doing a + b will give the desired result. If you really want to do this as a loop, then you can don't need to nest it - simply take a single index, i, to pull elements from both input vectors. Another option that might be helpful here is purrr::map2() which applies the specified function across two input lists.
However it's worth noting that if you did want to see all pairwise combinations, you could use the outer() function.
# test vectors
a = c(1,2,3,4)
b = c(2,3,4,5)
# operate pairwise through the two vectors
a + b
#> [1] 3 5 7 9
# go through vectors as a loop
for(i in seq_along(a)){
print(a[i] + b[i])
}
#> [1] 3
#> [1] 5
#> [1] 7
#> [1] 9
# for more complex function can use purrr::map2 to run on two input lists
purrr::map2_dbl(.x = a, .y = b, `+`)
#> [1] 3 5 7 9
# operate on all combinations
outer(a, b, `+`)
#> [,1] [,2] [,3] [,4]
#> [1,] 3 4 5 6
#> [2,] 4 5 6 7
#> [3,] 5 6 7 8
#> [4,] 6 7 8 9
Created on 2022-04-13 by the reprex package (v2.0.1)
Related
I have a list of three different types of datasets, with ten datasets in each type. It looks like this:
mat1 <- replicate(n=10,data.frame(matrix(data=rnorm(20,0,1),nrow=5,ncol=5)),simplify=FALSE)
mat2 <- replicate(n=10,data.frame(matrix(data=rnorm(20,0,1),nrow=5,ncol=5)),simplify=FALSE)
mat3 <- replicate(n=10,data.frame(matrix(data=rnorm(20,0,1),nrow=5,ncol=5)),simplify=FALSE)
combined <- list(mat1,mat2,mat3)
I want to apply the same function to each of the datasets, but I can't figure out how to access them. I tried using map from purrr, but it only applies it to the first one in the list:
map(combined[[i]],~length(.))
[[1]]
[1] 5
[[2]]
[1] 5
[[3]]
[1] 5
[[4]]
[1] 5
[[5]]
[1] 5
[[6]]
[1] 5
[[7]]
[1] 5
[[8]]
[1] 5
[[9]]
[1] 5
[[10]]
[1] 5
How can I apply a function to all datasets in a nested list?
*The function is more complex than length - it's a function from another package that I need to access using ~function
You can apply lengths on each list in combined :
lapply(combined, lengths)
#[[1]]
# [1] 5 5 5 5 5 5 5 5 5 5
#[[2]]
# [1] 5 5 5 5 5 5 5 5 5 5
#[[3]]
# [1] 5 5 5 5 5 5 5 5 5 5
Using purrr's map :
purrr::map(combined, lengths)
If length is just an example and you want a general way to apply a function to each nested list you may use nested lapply :
lapply(combined, function(x) lapply(x, function(y) length(y)))
Or use rapply :
rapply(combined, length, how = 'list')
Given a vector (column of a data frame), I'd like to create a rolling vector.
l = 0:10
Would return, (with a window of 3):
[0, 1, 2], [1, 2, 3], [2, 3, 4], [3, 4, 5] ...
1) rollapply r is a 9x3 matrix each of whose rows is one of the list elements asked for and split turns that into a list of vectors. Although this gives what you asked for it may be that you just want to iterate over that list and in that case it might be easier to just replace c with whatever function you wanted to use in that iteration. e.g. rollapply(l, 3, sd)
library(zoo)
l <- 0:10 # test input
r <- rollapply(l, 3, c)
split(r, row(r))
giving:
$`1`
[1] 0 1 2
$`2`
[1] 1 2 3
$`3`
[1] 2 3 4
$`4`
[1] 3 4 5
$`5`
[1] 4 5 6
$`6`
[1] 5 6 7
$`7`
[1] 6 7 8
$`8`
[1] 7 8 9
$`9`
[1] 8 9 10
2) embed This could also be done using base R like this:
r <- embed(l, 3)[, 3:1]
split(r, row(r))
You can use the following function (I am assuming you want the values to be sorted first. If not, just remove the line of code where I am using sort()) :
roll<-function(list,window){
list<-sort(list,decreasing = FALSE)
res<-vector(mode = "list")
for(i in 1:(length(list) - window + 1)){
res[[i]]<-list[i:(i + window - 1)]
}
return(res)
}
Enter your column/list values in the argument along with the window size you want and it should give you the desired output.
For example:
test<-0:10
roll(list = test,window = 3)
This results in the following output:
[[1]]
[1] 0 1 2
[[2]]
[1] 1 2 3
[[3]]
[1] 2 3 4
[[4]]
[1] 3 4 5
[[5]]
[1] 4 5 6
[[6]]
[1] 5 6 7
[[7]]
[1] 6 7 8
[[8]]
[1] 7 8 9
[[9]]
[1] 8 9 10
You can use this function for other cases and even change the window size as per your requirements.
Hope that helps!
I have the following list of numbers (1,3,4,5,7,9,10,12,15) and I want to find out all the possible combinations of 3 numbers from this list that would sum to 20.
My research on stackoverflow has led me to this post:
Finding all possible combinations of numbers to reach a given sum
There is a solution provided by Mark which stand as follows:
subset_sum = function(numbers,target,partial=0){
if(any(is.na(partial))) return()
s = sum(partial)
if(s == target) print(sprintf("sum(%s)=%s",paste(partial[-1],collapse="+"),target))
if(s > target) return()
for( i in seq_along(numbers)){
n = numbers[i]
remaining = numbers[(i+1):length(numbers)]
subset_sum(remaining,target,c(partial,n))
}
}
However I am having a hard time trying to tweak this set of codes to match my problem. Or may be there is a simpler solution?
I want the output in R to show me the list of numbers.
Any help would be appreciated.
You can use combn function and filter to meet your criteria. I have performed below calculation in 2 steps but one can perform it in single step too.
v <- c(1,3,4,5,7,9,10,12,15)
AllComb <- combn(v, 3) #generates all combination taking 3 at a time.
PossibleComb <- AllComb[,colSums(AllComb) == 20] #filter those with sum == 20
#Result: 6 sets of 3 numbers (column-wise)
PossibleComb
# [,1] [,2] [,3] [,4] [,5] [,6]
# [1,] 1 1 1 3 3 4
# [2,] 4 7 9 5 7 7
# [3,] 15 12 10 12 10 9
#
# Result in list
split(PossibleComb, col(PossibleComb))
# $`1`
# [1] 1 4 15
#
# $`2`
# [1] 1 7 12
#
# $`3`
# [1] 1 9 10
#
# $`4`
# [1] 3 5 12
#
# $`5`
# [1] 3 7 10
#
# $`6`
# [1] 4 7 9
The combn also have a FUN parameter which we can describe to output as list and then Filter the list elements based on the condition
Filter(function(x) sum(x) == 20, combn(v, 3, FUN = list))
#[[1]]
#[1] 1 4 15
#[[2]]
#[1] 1 7 12
#[[3]]
#[1] 1 9 10
#[[4]]
#[1] 3 5 12
#[[5]]
#[1] 3 7 10
#[[6]]
#[1] 4 7 9
data
v <- c(1,3,4,5,7,9,10,12,15)
Suppose we have a value y=4, and a list of vectors, I want to check if this value belongs to any vector in the list if yes, I will add this value to all the elements of vectors.
y<-4
M<- list( c(1,3,4,6) , c(2,3,5), c(1,3,6) ,c(1,4,5,6))
> M
[[1]]
[1] 1 3 4 6
[[2]]
[1] 2 3 5
[[3]]
[1] 1 3 6
[[4]]
[1] 1 4 5 6
The outcomes will be similar to :
> R
[[1]]
[1] 5 7 8 10
[[2]]
[1] 5 8 9 10
We can use keep which only keeps elements that satisfy a predicate. In this case, it is only keeping the vectors that contain y.
We then add y to each of the vectors.
library('tidyverse')
keep(M, ~y %in% .) %>%
map(~. + y)
Here is a simple hacky way to do this:
lapply(M[sapply(M, function(x){y %in% x})],function(x){x+y})
returning:
[[1]]
[1] 5 7 8 10
[[2]]
[1] 5 8 9 10
Logic: use sapply to work out which parts of M have a 4 in, then add 4 to those with lapply
You can do this with...
lapply(M[sapply(M, `%in%`, x=y)], `+`, y)
[[1]]
[1] 5 7 8 10
[[2]]
[1] 5 8 9 10
Here is a method with lapply and set functions.
# loop through M, check length of intersect
myList <- lapply(M, function(x) if(length(intersect(y, x)) > 0) x + y else NULL)
# now subset, dropping the NULL elements
myList <- myList[lengths(myList) > 0]
this returns
myList
[[1]]
[1] 5 7 8 10
[[2]]
[1] 5 8 9 10
Wow! everyone has given great answers, just including the use of Map functionality.
Map("+",M[unlist(Map("%in%", y,M))],y)
[[1]]
[1] 5 7 8 10
[[2]]
[1] 5 8 9 10
I want to enumerate the distinct sequences of different permutations, and I'm using the function permn. I understand for 2!, I can just use permn(2) and that will enumerate 1, 2 and 2, 1.
> library(combinat)
> permn(2)
[[1]]
[1] 1 2
[[2]]
[1] 2 1
I want to do the same thing for the numbers 7 and 8. So what should I pass into the function so that it will return something like this?
> permn(...)
[[1]]
[1] 7 8
[[2]]
[1] 8 7
permn(c(7,8))
#[[1]]
#[1] 7 8
#
#[[2]]
#[1] 8 7