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
Related
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)
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!
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
This question already has answers here:
Create grouping variable for consecutive sequences and split vector
(5 answers)
Closed 5 years ago.
The following vector x contains the two sequences 1:4 and 6:7, among other non-sequential digits.
x <- c(7, 1:4, 6:7, 9)
I'd like to split x by its sequences, so that the result is a list like the following.
# [[1]]
# [1] 7
#
# [[2]]
# [1] 1 2 3 4
#
# [[3]]
# [1] 6 7
#
# [[4]]
# [1] 9
Is there a quick and simple way to do this?
I've tried
split(x, c(0, diff(x)))
which gets close, but I don't feel like appending 0 to the differenced vector is the right way to go. Using findInterval didn't work either.
split(x, cumsum(c(TRUE, diff(x)!=1)))
#$`1`
#[1] 7
#
#$`2`
#[1] 1 2 3 4
#
#$`3`
#[1] 6 7
#
#$`4`
#[1] 9
Just for fun, you can make use of Carl Witthoft's seqle function from his "cgwtools" package. (It's not going to be anywhere near as efficient as Roland's answer.)
library(cgwtools)
## Here's what seqle does...
## It's like rle, but for sequences
seqle(x)
# Run Length Encoding
# lengths: int [1:4] 1 4 2 1
# values : num [1:4] 7 1 6 9
y <- seqle(x)
split(x, rep(seq_along(y$lengths), y$lengths))
# $`1`
# [1] 7
#
# $`2`
# [1] 1 2 3 4
#
# $`3`
# [1] 6 7
#
# $`4`
# [1] 9