Getting all splits of numeric sequence in R - r

I'm trying to get all the possible splits of a sequence [1:n] in R. E.g.:
getSplits(0,3)
Should return all possible splits of the sequence 123, in other words (in a list of vectors):
[1] 1
[2] 1 2
[3] 1 2 3
[4] 1 3
[5] 2
[6] 2 3
[7] 3
Now I've created a function which does get to these vectors recursively, but having trouble combining them into one as above. My function is:
getSplits <- function(currentDigit, lastDigit, split) {
splits=list();
for (nextDigit in currentDigit: lastDigit)
{
currentSplit <- c(split, c(nextDigit));
print(currentSplit);
if(nextDigit < lastDigit) {
possibleSplits = c(list(currentSplit), getSplits(nextDigit+1, lastDigit, currentSplit));
}else{
possibleSplits = currentSplit;
}
splits <- c(splits, list(possibleSplits));
}
return(splits);
}
Where printing each currentSplit results in all the right vectors I need, but somehow the final returnt list (splits) nests them into deeper levels of lists, returning:
[1] 1
[[1]][[2]]
[[1]][[2]][[1]]
[1] 1 2
[[1]][[2]][[2]]
[1] 1 2 3
[[1]][[3]]
[1] 1 3
[[2]]
[[2]][[1]]
[1] 2
[[2]][[2]]
[1] 2 3
[[3]]
[1] 3
For the corresponding function call getSplits(1, 3, c()).
If anyone could help me out on getting this to work the way I described above, it'd be much appreciated!

character vector output
Try combn:
k <- 3
s <- unlist(lapply(1:k, combn, x = k, toString))
s
## [1] "1" "2" "3" "1, 2" "1, 3" "2, 3" "1, 2, 3"
data frame output
If you would prefer that the output be in the form of a data frame:
read.table(text = s, header = FALSE, sep = ",", fill = TRUE, col.names = 1:k)
giving:
X1 X2 X3
1 1 NA NA
2 2 NA NA
3 3 NA NA
4 1 2 NA
5 1 3 NA
6 2 3 NA
7 1 2 3
list output
or a list:
lapply(s, function(x) scan(textConnection(x), quiet = TRUE, sep = ","))
giving:
[[1]]
[1] 1
[[2]]
[1] 2
[[3]]
[1] 3
[[4]]
[1] 1 2
[[5]]
[1] 1 3
[[6]]
[1] 2 3
[[7]]
[1] 1 2 3
Update: Have incorporated improvement mentioned in comments as well as one further simplification and also added data frame and list output.

Here is another approach:
f <- function(nums) sapply(1:length(nums), function(x) t(combn(nums, m = x)))
f(1:3)
This yields
[[1]]
[,1]
[1,] 1
[2,] 2
[3,] 3
[[2]]
[,1] [,2]
[1,] 1 2
[2,] 1 3
[3,] 2 3
[[3]]
[,1] [,2] [,3]
[1,] 1 2 3

The OP is looking for the Power set of c(1,2,3). There are several packages that will quickly get you this in one line. Using the package rje, we have:
library(rje)
powerSet(c(1,2,3))
[[1]]
numeric(0)
[[2]]
[1] 1
[[3]]
[1] 2
[[4]]
[1] 1 2
[[5]]
[1] 3
[[6]]
[1] 1 3
[[7]]
[1] 2 3
[[8]]
[1] 1 2 3
... and with iterpc:
library(iterpc)
getall(iterpc(c(2,1,1,1), 3, labels = 0:3))
[,1] [,2] [,3]
[1,] 0 0 1
[2,] 0 0 2
[3,] 0 0 3
[4,] 0 1 2
[5,] 0 1 3
[6,] 0 2 3
[7,] 1 2 3
More generally,
n <- 3
getall(iterpc(c(n-1,rep(1, n)), n, labels = 0:n)) ## same as above

Related

Imitate `simplify=F` in `apply()` for versions of R < 4.1.0

Given a binary matrix, I want to generate a list of the positions of the 1s by row. For example:
> M <- matrix(c(1,1,0,0,1,1,1,0,1), 3, 3)
> M
[,1] [,2] [,3]
[1,] 1 0 1
[2,] 1 1 0
[3,] 0 1 1
> apply(M==1, 1, which, simplify = FALSE)
[[1]]
[1] 1 3
[[2]]
[1] 1 2
[[3]]
[1] 2 3
However, in versions of R before 4.1.0, the apply() function automatically simplifies, which means the result will sometimes not be a list, but gets simplified into a vector or matrix. For example:
> apply(M==1, 1, which)
[,1] [,2] [,3]
[1,] 1 1 2
[2,] 3 2 3
How can I ensure the output will always be a list, even in earlier versions of R when the simplify = F parameter isn't available for apply()? Thanks!
You can use asplit, which splits the matrix into a list of vectors by the selected margin. Then use lapply on the result to apply the which to each vector.
lapply(asplit(M == 1, 1), which)
#> [[1]]
#> [1] 1 3
#>
#> [[2]]
#> [1] 1 2
#>
#> [[3]]
#> [1] 2 3
We may use which with arr.ind = TRUE and then split by the 'row'
ind <- which(M == 1, arr.ind = TRUE)
split(ind[,2], ind[, 1])
$`1`
[1] 1 3
$`2`
[1] 1 2
$`3`
[1] 2 3

Find all combinations of the numbers in a vector. R programming

Are there any direct functions that can be used to get the combinations of all the items in the vector?
myVector <- c(1,2,3)
for (i in myVector)
for (j in myVector)
for (k in myVector)
print(paste(i,j,k,sep=","))
The screenshot of the first part of the output look like this. As there are three values 1,2,3 there will be
3 * 3 * 3 = 27 lines
I tried to get the permutations using the function permn() as,
permn(myVector)
But is giving only the 9 different values.
Screenshot of the output :
Is there any direct function that can produce such a result as shown in the first?
Using RcppAlgos::permuteGeneral.
r <- RcppAlgos::permuteGeneral(myVector, length(myVector), repetition=TRUE)
head(r, 3)
# [,1] [,2] [,3]
# [1,] 1 1 1
# [2,] 1 1 2
# [3,] 1 1 3
If you want the comma separated strings, do
apply(r, 1, paste, collapse=",")
# [1] "1,1,1" "1,1,2" "1,1,3" "1,2,1" "1,2,2" "1,2,3" "1,3,1"
# [8] "1,3,2" "1,3,3" "2,1,1" "2,1,2" "2,1,3" "2,2,1" "2,2,2"
# [15] "2,2,3" "2,3,1" "2,3,2" "2,3,3" "3,1,1" "3,1,2" "3,1,3"
# [22] "3,2,1" "3,2,2" "3,2,3" "3,3,1" "3,3,2" "3,3,3"
Or the list output, you've also shown
RcppAlgos::permuteGeneral(myVector, length(myVector), FUN=function(x)
paste(x, collapse=","), repetition=TRUE)
# [[1]]
# [1] "1,1,1"
#
# [[2]]
# [1] "1,1,2"
#
# [[3]]
# [1] "1,1,3"
#
# [[4]]
# [1] "1,2,1"
# ...
You may decide on your own :)
Use expand.grid :
tmp <- expand.grid(myVector, myVector, myVector)
tmp
# Var1 Var2 Var3
#1 1 1 1
#2 2 1 1
#3 3 1 1
#4 1 2 1
#5 2 2 1
#6 3 2 1
#...
#...
If you want to do this automatically for the length of myVector without manually specifying it 3 times you can use replicate.
tmp <- do.call(expand.grid, replicate(length(myVector),
myVector, simplify = FALSE))
To paste the values together you can do :
do.call(paste, c(tmp, sep = ','))
# [1] "1,1,1" "2,1,1" "3,1,1" "1,2,1" "2,2,1" "3,2,1" "1,3,1" "2,3,1"
# [9] "3,3,1" "1,1,2" "2,1,2" "3,1,2" "1,2,2" "2,2,2" "3,2,2" "1,3,2"
#[17] "2,3,2" "3,3,2" "1,1,3" "2,1,3" "3,1,3" "1,2,3" "2,2,3" "3,2,3"
#[25] "1,3,3" "2,3,3" "3,3,3"
Note that there is a permutations function in the gtools package that allows you to generalize permutation outputs:
library(gtools)
permutations(3, 3, 1:3, repeats.allowed = TRUE)
[,1] [,2] [,3]
[1,] 1 1 1
[2,] 1 1 2
[3,] 1 1 3
[4,] 1 2 1
[5,] 1 2 2
[6,] 1 2 3
[7,] 1 3 1
[8,] 1 3 2
[9,] 1 3 3
[10,] 2 1 1
The function help describes the parameter settings.
It appears that pracma::combs does exactly this. That, and pracma::perms generate output sets which treat every element of the input as distinct, regardless of whether a value is repeated.

multiply two lists of irregular length

I have lists like
a <- list(list(c(-2,1), 4:5, 2:3), list(c(0,2), c(-1,1)))
b <- list(7:9, c(5,-1))
> a
[[1]]
[[1]][[1]]
[1] -2 1
[[1]][[2]]
[1] 4 5
[[1]][[3]]
[1] 2 3
[[2]]
[[2]][[1]]
[1] 0 2
[[2]][[2]]
[1] -1 1
> b
[[1]]
[1] 7 8 9
[[2]]
[1] 5 -1
I want to multiply each of (-2, 1) from a[[1] with 7 from b[[1]] to get (-14, 7), each of (4, 5) with 8, each of (2, 3) with 9, and then each of (0, 2) with 5 and finally each of (-1, 1), with -1.
I can be sure that length(a[[i]])==length(b[[i]]) is TRUE for i=1,2 (in practice, i is way larger), so that there are the right number of entries for the desired multiplications.
However, it is not clear how many entries the a[[i]]) have (in the example, 3 for a[[1]] and 2 for a[[2]], or equivalently, how long the b[[i]] are), except that they'll have at least one entry. Hence, transforming a and b into matrices does not seem practical.
I am not sure that is relevant to the problem, but it will also be the case that we have as many entries in each of the a[[i]]) (i.e., 2) as we have a[[i]])s.
I was thinking of some combination of do.call and mapply, but could not get it to work.
We may indeed use mapply (and Map, which is the same as mapply but with SIMPLIFY = FALSE). Depending on the format (matrix as in #RonakShah's answer or a list as in your question), you may use
Map(mapply, a, b, MoreArgs = list(FUN = `*`))
# [[1]]
# [,1] [,2] [,3]
# [1,] -14 32 18
# [2,] 7 40 27
#
# [[2]]
# [,1] [,2]
# [1,] 0 1
# [2,] 10 -1
or
Map(Map, a, b, MoreArgs = list(f = `*`))
# [[1]]
# [[1]][[1]]
# [1] -14 7
#
# [[1]][[2]]
# [1] 32 40
#
# [[1]][[3]]
# [1] 18 27
#
#
#[[2]]
# [[2]][[1]]
# [1] 0 10
#
# [[2]][[2]]
# [1] 1 -1
A tidyverse alternative to the latter is
map2(a, b, map2, `*`)
Since, you can ensure length(a[[i]])==length(b[[i]]) we can use mapply inside lapply
lapply(seq_along(a), function(x) mapply("*", a[[x]], b[[x]]))
#[[1]]
# [,1] [,2] [,3]
#[1,] -14 32 18
#[2,] 7 40 27
#[[2]]
# [,1] [,2]
#[1,] 0 1
#[2,] 10 -1

Conditional merging of two lists in R

I am trying to combine two lists that complement each other, where one contains half the set of values and the second the other half:
v1 <- c(1,2,2,4)
v2 <- c(NULL)
v3 <- c(1,2,2,4)
l1 <- list(v1,v2,v3)
v1b <- c(NULL)
v2b <- c(1,2,2,4)
v3b <- c(NULL)
l2 <- list(v1b,v2b,v3b)
> l1
[[1]]
[1] 1 2 2 4
[[2]]
NULL
[[3]]
[1] 1 2 2 4
> l2
[[1]]
NULL
[[2]]
[1] 1 2 2 4
[[3]]
NULL
The desired result is:
[[1]]
[1] 1 2 2 4
[[2]]
[1] 1 2 2 4
[[3]]
[1] 1 2 2 4
I tried several ways. This is the closest I got:
> sapply(l1, function(x) ifelse(x == "NULL", l2[[x]], x))
[[1]]
[1] 1 2 2 4
[[2]]
logical(0)
[[3]]
[1] 1 2 2 4
Any help is appreciated.

replicate function in R returns NULL

I am confused about the output from the replicate function in R, I am trying to use it in two different ways, that (in my mind) should give a matrix as output!
so, if I use
replicate(5, seq(1,5,1))
I get a matrix 5x5
[,1] [,2] [,3] [,4] [,5]
[1,] 1 1 1 1 1
[2,] 2 2 2 2 2
[3,] 3 3 3 3 3
[4,] 4 4 4 4 4
[5,] 5 5 5 5 5
..and that's ok, I get that...
but, if I instead use:
replicate(5, for(i in 1:5){print(i)})
I get the following:
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[[1]]
NULL
[[2]]
NULL
[[3]]
NULL
[[4]]
NULL
[[5]]
NULL
can anyone explain me why does this happen?
thanks :)
A for loop returns NULL. So in the second case, the replicate function is executing for(i in 1:5){print(i)} five times, which is why you see all those numbers printed out.
Then it is putting the return values in a list, so the return value of the replicate call is a list of five NULLs, which gets printed out. Executing
x<-replicate(5, for(i in 1:5){print(i)})
x
should clarify.
As #mrip says a for-loop returns NULL so you need to assign to an object within the loop, and return that object to replicate so it can be output. However, mrip's code still results in NULLs from each iteration of the replicate evaluation.
You also need to assign the output of replicate to a name, so it doesn't just evaporate, er, get garbage collected. That means you need to add the d as a separate statement so that the evaluation of the whole expression inside the curley-braces will return 'something' rather than NULL.
d <- numeric(5); res <- replicate(5, {
for(i in 1:5){d[i] <- print(i)} ; d}
)
[1] 1
[1] 2
snipped
[1] 4
[1] 5
> res
[,1] [,2] [,3] [,4] [,5]
[1,] 1 1 1 1 1
[2,] 2 2 2 2 2
[3,] 3 3 3 3 3
[4,] 4 4 4 4 4
[5,] 5 5 5 5 5
The for loop is giving a list back, while the seq() call is giving a vector back. This should give you the same as the seq() using a for loop
foo <- function(){
b = list()
for(i in 1:5) b[i] <- i
do.call(c, b)
}
replicate(5, foo())

Resources