I'm trying to create a list of permutations of a list, such that, for example, perms(list("a", "b", "c")) returns
list(list("a", "b", "c"), list("a", "c", "b"), list("b", "a", "c"),
list("b", "c", "a"), list("c", "a", "b"), list("c", "b", "a"))
I'm not sure how to proceed, any help would be greatly appreciated.
A while back I had to do this in base R without loading any packages.
permutations <- function(n){
if(n==1){
return(matrix(1))
} else {
sp <- permutations(n-1)
p <- nrow(sp)
A <- matrix(nrow=n*p,ncol=n)
for(i in 1:n){
A[(i-1)*p+1:p,] <- cbind(i,sp+(sp>=i))
}
return(A)
}
}
Usage:
> matrix(letters[permutations(3)],ncol=3)
[,1] [,2] [,3]
[1,] "a" "b" "c"
[2,] "a" "c" "b"
[3,] "b" "a" "c"
[4,] "b" "c" "a"
[5,] "c" "a" "b"
[6,] "c" "b" "a"
combinat::permn will do that work:
> library(combinat)
> permn(letters[1:3])
[[1]]
[1] "a" "b" "c"
[[2]]
[1] "a" "c" "b"
[[3]]
[1] "c" "a" "b"
[[4]]
[1] "c" "b" "a"
[[5]]
[1] "b" "c" "a"
[[6]]
[1] "b" "a" "c"
Note that calculation is huge if the element is large.
base R can also provide the answer:
all <- expand.grid(p1 = letters[1:3], p2 = letters[1:3], p3 = letters[1:3], stringsAsFactors = FALSE)
perms <- all[apply(all, 1, function(x) {length(unique(x)) == 3}),]
You can try permutations() from the gtools package, but unlike permn() from combinat, it doesn't output a list:
> library(gtools)
> permutations(3, 3, letters[1:3])
[,1] [,2] [,3]
[1,] "a" "b" "c"
[2,] "a" "c" "b"
[3,] "b" "a" "c"
[4,] "b" "c" "a"
[5,] "c" "a" "b"
[6,] "c" "b" "a"
A solution in base R, no dependencies on other packages:
> getPermutations <- function(x) {
if (length(x) == 1) {
return(x)
}
else {
res <- matrix(nrow = 0, ncol = length(x))
for (i in seq_along(x)) {
res <- rbind(res, cbind(x[i], Recall(x[-i])))
}
return(res)
}
}
> getPermutations(letters[1:3])
[,1] [,2] [,3]
[1,] "a" "b" "c"
[2,] "a" "c" "b"
[3,] "b" "a" "c"
[4,] "b" "c" "a"
[5,] "c" "a" "b"
[6,] "c" "b" "a"
I hope this helps.
# Another recursive implementation
# for those who like to roll their own, no package required
permutations <- function( x, prefix = c() )
{
if(length(x) == 0 ) return(prefix)
do.call(rbind, sapply(1:length(x), FUN = function(idx) permutations( x[-idx], c( prefix, x[idx])), simplify = FALSE))
}
permutations(letters[1:3])
# [,1] [,2] [,3]
#[1,] "a" "b" "c"
#[2,] "a" "c" "b"
#[3,] "b" "a" "c"
#[4,] "b" "c" "a"
#[5,] "c" "a" "b"
#[6,] "c" "b" "a"
Try:
> a = letters[1:3]
> eg = expand.grid(a,a,a)
> eg[!(eg$Var1==eg$Var2 | eg$Var2==eg$Var3 | eg$Var1==eg$Var3),]
Var1 Var2 Var3
6 c b a
8 b c a
12 c a b
16 a c b
20 b a c
22 a b c
As suggested by #Adrian in comments, last line can be replaced by:
eg[apply(eg, 1, anyDuplicated) == 0, ]
A fun solution "probabilistic" using sample for base R:
elements <- c("a", "b", "c")
k <- length(elements)
res=unique(t(sapply(1:200, function(x) sample(elements, k))))
# below, check you have all the permutations you need (if not, try again)
nrow(res) == factorial(k)
res
basically you call many random samples, hoping to get them all, and you unique them.
We can use base function combn with a little modifcation:
combn_n <- function(x) {
m <- length(x) - 1 # number of elements to choose: n-1
xr <- rev(x) # reversed x
part_1 <- rbind(combn(x, m), xr, deparse.level = 0)
part_2 <- rbind(combn(xr, m), x, deparse.level = 0)
cbind(part_1, part_2)
}
combn_n(letters[1:3])
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] "a" "a" "b" "c" "c" "b"
[2,] "b" "c" "c" "b" "a" "a"
[3,] "c" "b" "a" "a" "b" "c"
Behold, the purrr 🐾 solution:
> map(1:3, ~ c('a', 'b', 'c')) %>%
cross() %>%
keep(~ length(unique(.x)) == 3) %>%
map(unlist)
#> [[1]]
#> [1] "c" "b" "a"
#>
#> [[2]]
#> [1] "b" "c" "a"
#>
#> [[3]]
#> [1] "c" "a" "b"
#>
#> [[4]]
#> [1] "a" "c" "b"
#>
#> [[5]]
#> [1] "b" "a" "c"
#>
#> [[6]]
#> [1] "a" "b" "c"
In case this helps, there is the "arrangements" package, that allows you to simply do :
> abc = letters[1:3]
> permutations(abc)
[,1] [,2] [,3]
[1,] "a" "b" "c"
[2,] "a" "c" "b"
[3,] "b" "a" "c"
[4,] "b" "c" "a"
[5,] "c" "a" "b"
[6,] "c" "b" "a"
A generic version of rnso's answer is:
get_perms <- function(x){
stopifnot(is.atomic(x)) # for the matrix call to make sense
out <- as.matrix(expand.grid(
replicate(length(x), x, simplify = FALSE), stringsAsFactors = FALSE))
out[apply(out,1, anyDuplicated) == 0, ]
}
Here are two examples:
get_perms(letters[1:3])
#R> Var1 Var2 Var3
#R> [1,] "c" "b" "a"
#R> [2,] "b" "c" "a"
#R> [3,] "c" "a" "b"
#R> [4,] "a" "c" "b"
#R> [5,] "b" "a" "c"
#R> [6,] "a" "b" "c"
get_perms(letters[1:4])
#R> Var1 Var2 Var3 Var4
#R> [1,] "d" "c" "b" "a"
#R> [2,] "c" "d" "b" "a"
#R> [3,] "d" "b" "c" "a"
#R> [4,] "b" "d" "c" "a"
#R> [5,] "c" "b" "d" "a"
#R> [6,] "b" "c" "d" "a"
#R> [7,] "d" "c" "a" "b"
#R> [8,] "c" "d" "a" "b"
#R> [9,] "d" "a" "c" "b"
#R> [10,] "a" "d" "c" "b"
#R> [11,] "c" "a" "d" "b"
#R> [12,] "a" "c" "d" "b"
#R> [13,] "d" "b" "a" "c"
#R> [14,] "b" "d" "a" "c"
#R> [15,] "d" "a" "b" "c"
#R> [16,] "a" "d" "b" "c"
#R> [17,] "b" "a" "d" "c"
#R> [18,] "a" "b" "d" "c"
#R> [19,] "c" "b" "a" "d"
#R> [20,] "b" "c" "a" "d"
#R> [21,] "c" "a" "b" "d"
#R> [22,] "a" "c" "b" "d"
#R> [23,] "b" "a" "c" "d"
#R> [24,] "a" "b" "c" "d"
One can also slightly alter Rick's answer by using lapply, only doing a single rbind, and reduce the number of [s]/[l]apply calls:
permutations <- function(x, prefix = c()){
if(length(x) == 1) # was zero before
return(list(c(prefix, x)))
out <- do.call(c, lapply(1:length(x), function(idx)
permutations(x[-idx], c(prefix, x[idx]))))
if(length(prefix) > 0L)
return(out)
do.call(rbind, out)
}
What about
pmsa <- function(l) {
pms <- function(n) if(n==1) return(list(1)) else unlist(lapply(pms(n-1),function(v) lapply(0:(n-1),function(k) append(v,n,k))),recursive = F)
lapply(pms(length(l)),function(.) l[.])
}
This gives a list. Then
pmsa(letters[1:3])
Related
How to randomize values in an R matrix
For example, here is what I Would like to randomize
A, A, A, A, A
B, B, B, B, B
C, C, C, C, C
D, D, D, D, D
E, E, E, E, E
F, F, F, F, F
G, G, G, G, G
I'd recommend a random process that checks for dupes and reruns columns as needed.
myfunc <- function(nrow = 7, ncol = 4, iters = 500) {
m <- matrix("", nrow = nrow, ncol = ncol)
len <- seq_len(nrow)
m[,1] <- sample(LETTERS[len])
iter <- 0
for (col in seq_len(ncol)[-1]) {
iter <- iter + 1
if (iter > iters) break
m[,col] <- sample(LETTERS[len])
while (any(m[,col] == m[,-col])) {
iter <- iter + 1
if (iter > iters) break
m[,col] <- sample(LETTERS[len])
}
}
attr(m, "iter") <- iter
m
}
set.seed(42)
myfunc()
# [,1] [,2] [,3] [,4]
# [1,] "A" "B" "F" "D"
# [2,] "E" "G" "A" "C"
# [3,] "G" "C" "B" "A"
# [4,] "F" "A" "C" "G"
# [5,] "B" "D" "E" "F"
# [6,] "C" "E" "D" "B"
# [7,] "D" "F" "G" "E"
# attr(,"iter")
# [1] 69
I added the internal iter counting just so that we'd know how many times it took. And I added the iters limit so that it would not go on forever with ridiculous combinations; you'll know it hit the limit when one or more columns are empty strings "":
myfunc(7,7)
# [,1] [,2] [,3] [,4] [,5] [,6] [,7]
# [1,] "D" "E" "G" "B" "A" "C" "G"
# [2,] "B" "A" "D" "G" "E" "F" "C"
# [3,] "C" "D" "F" "A" "G" "E" "E"
# [4,] "E" "B" "C" "D" "F" "A" "B"
# [5,] "F" "G" "E" "C" "B" "D" "F"
# [6,] "A" "C" "B" "F" "D" "G" "A"
# [7,] "G" "F" "A" "E" "C" "B" "D"
# attr(,"iter")
# [1] 501
myfunc(7,7)
# [,1] [,2] [,3] [,4] [,5] [,6] [,7]
# [1,] "D" "E" "C" "F" "G" "B" ""
# [2,] "G" "D" "E" "A" "F" "C" ""
# [3,] "F" "A" "B" "G" "D" "A" ""
# [4,] "E" "B" "F" "D" "C" "D" ""
# [5,] "A" "C" "G" "B" "E" "E" ""
# [6,] "C" "F" "A" "E" "B" "F" ""
# [7,] "B" "G" "D" "C" "A" "G" ""
# attr(,"iter")
# [1] 502
Your shifting approach you may realize like so.
mapply(function(x, y) x[(seq(x) + y - 1) %% nrow(m)], as.data.frame(m), 1:ncol(m))
# V1 V2 V3 V4
# [1,] "A" "B" "C" "D"
# [2,] "B" "C" "D" "E"
# [3,] "C" "D" "E" "F"
# [4,] "D" "E" "F" "A"
# [5,] "E" "F" "A" "B"
# [6,] "F" "A" "B" "C"
Data:
m <- structure(c("A", "B", "C", "D", "E", "F", "G", "A", "B", "C",
"D", "E", "F", "G", "A", "B", "C", "D", "E", "F", "G", "A", "B",
"C", "D", "E", "F", "G"), .Dim = c(7L, 4L))
To get a deterministic permutation, create the matrix and fill it in using the row() and col() functions. For example,
rotated <- function(r, c, symbols = NULL) {
num <- max(r, c)
m <- matrix(NA, r, c)
m <- (row(m) + col(m) - 2) %% num + 1
if (!is.null(symbols)) {
m <- symbols[m]
dim(m) <- c(r,c)
}
m
}
rotated(7, 4, LETTERS)
#> [,1] [,2] [,3] [,4]
#> [1,] "A" "B" "C" "D"
#> [2,] "B" "C" "D" "E"
#> [3,] "C" "D" "E" "F"
#> [4,] "D" "E" "F" "G"
#> [5,] "E" "F" "G" "A"
#> [6,] "F" "G" "A" "B"
#> [7,] "G" "A" "B" "C"
Created on 2020-10-07 by the reprex package (v0.3.0)
If you want it randomized, permute rows and columns randomly:
rotated(7, 4, LETTERS)[sample(7), sample(4)]
#> [,1] [,2] [,3] [,4]
#> [1,] "B" "D" "C" "A"
#> [2,] "F" "A" "G" "E"
#> [3,] "E" "G" "F" "D"
#> [4,] "A" "C" "B" "G"
#> [5,] "G" "B" "A" "F"
#> [6,] "C" "E" "D" "B"
#> [7,] "D" "F" "E" "C"
Assume we have the following permutations of the letters, "a", "b", and "c":
library(combinat)
do.call(rbind, permn(letters[1:3]))
# [,1] [,2] [,3]
# [1,] "a" "b" "c"
# [2,] "a" "c" "b"
# [3,] "c" "a" "b"
# [4,] "c" "b" "a"
# [5,] "b" "c" "a"
# [6,] "b" "a" "c"
Is it possible to perform some function on a given permutation "on-the-fly" (i.e., a particular row) without storing the result?
That is, if the row == "a" "c" "b" or row == "b" "c" "a", do not store the result. The desired result in this case would be:
# [,1] [,2] [,3]
# [1,] "a" "b" "c"
# [2,] "c" "a" "b"
# [3,] "c" "b" "a"
# [4,] "b" "a" "c"
I know I can apply a function to all the permutations on the fly within combinat::permn with the fun argument such as:
permn(letters[1:3], fun = function(x) {
res <- paste0(x, collapse = "")
if (res == "acb" | res == "bca") {
return(NA)
} else {
return(res)
}
})
But this stills stores an NA and the returned list has 6 elements instead of the desired 4 elements:
# [[1]]
# [1] "abc"
#
# [[2]]
# [1] NA
#
# [[3]]
# [1] "cab"
#
# [[4]]
# [1] "cba"
#
# [[5]]
# [1] NA
#
# [[6]]
# [1] "bac"
Note, I am not interested in subsequently removing the NA values; I am specifically interested in not appending to the result list "on-the-fly" for a given permutation.
We could use a magrittr pipeline where we rbind the input matrix to the Rows to be checked and omit the duplicate rows.
library(combinat)
library(magrittr)
Rows <- rbind(c("a", "c", "b"), c("b", "c", "a"))
do.call(rbind, permn(letters[1:3])) %>%
subset(tail(!duplicated(rbind(Rows, .)), -nrow(Rows)))
giving:
[,1] [,2] [,3]
[1,] "a" "b" "c"
[2,] "c" "a" "b"
[3,] "c" "b" "a"
[4,] "b" "a" "c"
You can return NULL for the particular condition that you want to ignore and rbind the result which will ignore the NULL elements and bind only the combinations that you need.
do.call(rbind, combinat::permn(letters[1:3], function(x)
if(!all(x == c("a", "c", "b") | x == c("b", "c", "a")))
return(x)
))
# [,1] [,2] [,3]
#[1,] "a" "b" "c"
#[2,] "c" "a" "b"
#[3,] "c" "b" "a"
#[4,] "b" "a" "c"
Similarly,
do.call(rbind, permn(letters[1:3],function(x) {
res <- paste0(x, collapse = "")
if (!res %in% c("acb","bca"))
return(res)
}))
# [,1]
#[1,] "abc"
#[2,] "cab"
#[3,] "cba"
#[4,] "bac"
I need to an R code for circular permutation of similar objects which defines this code exactly.
The number of circular permutations that can be formed using 'n' objects out of which 'p' are identical and of one kind and 'q' are identical and of another kind.
(n-1)!/p!q!
This is the best code which I found but it is not exactly what I want
library(arrangements)
permutations(x = c("A","B","C"), freq = c(2,1,1))
output:
[,1] [,2] [,3] [,4]
[1,] "A" "A" "B" "C"
[2,] "A" "A" "C" "B"
[3,] "A" "B" "A" "C"
[4,] "A" "B" "C" "A"
[5,] "A" "C" "A" "B"
[6,] "A" "C" "B" "A"
[7,] "B" "A" "A" "C"
[8,] "B" "A" "C" "A"
[9,] "B" "C" "A" "A"
[10,] "C" "A" "A" "B"
[11,] "C" "A" "B" "A"
[12,] "C" "B" "A" "A"
I do not want "A" "A" are beside each other.
It turns out that a recursive function works well for this problem. The function takes the journey so far, figures out which remaining towns are possible to visit next, and then calls itself for each of these. If there are no remaining towns it reports the route.
# recursive function to visit remaining towns
journey <- function(remaining, visited){
# possible towns to visit next
possible <- setdiff(remaining, tail(visited, 1))
if (length(possible)==0){
if (length(remaining)==0){
# report and store journey
print(visited)
routei <<- routei + 1
routes[[routei]] <<- visited
} else {
# route failed to visit all towns
}
} else {
# loop through options
for (i in possible){
# continue journey
journey(remaining[-match(i, remaining)], c(visited, i))
}
}
}
remaining <- c("A", "A", "B", "B", "C")
visited <- character(0)
routes <- vector("list", length(remaining)^2)
routei <- 0
journey(remaining, visited)
#> [1] "A" "B" "A" "B" "C"
#> [1] "A" "B" "A" "C" "B"
#> [1] "A" "B" "C" "A" "B"
#> [1] "A" "B" "C" "B" "A"
#> [1] "A" "C" "B" "A" "B"
#> [1] "B" "A" "B" "A" "C"
#> [1] "B" "A" "B" "C" "A"
#> [1] "B" "A" "C" "A" "B"
#> [1] "B" "A" "C" "B" "A"
#> [1] "B" "C" "A" "B" "A"
#> [1] "C" "A" "B" "A" "B"
#> [1] "C" "B" "A" "B" "A"
Created on 2019-07-22 by the reprex package (v0.3.0)
Consider a vector:
dim <- c("a", "b", "c", "d")
I want to be able to create versions of the vector by dropping some variables and then using the updated vector for my loop.
For eg:
I want it to iterate to all possible vectors that can results from this:
dim <- c("a", "b", "d")
So on and so forth. Could I do this in a loop or someway that I do not have to specify anything. Order doesn't matter, so I do not want a,b,c and c,a,b
You can get this with:
dim <- c("a", "b", "c", "d")
> Map(combn, list(dim), 1:length(dim))
[[1]] # All combinations of size 1
[,1] [,2] [,3] [,4]
[1,] "a" "b" "c" "d"
[[2]] # All combinations of size 2
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] "a" "a" "a" "b" "b" "c"
[2,] "b" "c" "d" "c" "d" "d"
[[3]] # All combinations of size 3
[,1] [,2] [,3] [,4]
[1,] "a" "a" "a" "b"
[2,] "b" "b" "c" "c"
[3,] "c" "d" "d" "d"
[[4]] # All combinations of size 4
[,1]
[1,] "a"
[2,] "b"
[3,] "c"
[4,] "d"
if you are looking for all combinations of dim you can check out the function combn from the combinat package:
combinat::combn(letters[1:4], 1, simplify = F)
[[1]]
[1] "a"
[[2]]
[1] "b"
[[3]]
[1] "c"
[[4]]
[1] "d"
combinat::combn(letters[1:4], 2, simplify = F)
combinat::combn(letters[1:4], 3, simplify = F)
combinat::combn(letters[1:4], 4, simplify = F)
In base R I would use either of the for-loop, sapply or lapply
for-loop
for (i in seq_along(dim)) {
print(dim[-i])
}
[1] "b" "c" "d"
[1] "a" "c" "d"
[1] "a" "b" "d"
[1] "a" "b" "c"
sapply
t( sapply(seq_along(dim), function(i) dim[-i]) )
[,1] [,2] [,3]
[1,] "b" "c" "d"
[2,] "a" "c" "d"
[3,] "a" "b" "d"
[4,] "a" "b" "c"
lapply
lapply(seq_along(dim), function(i) dim[-i])
[[1]]
[1] "b" "c" "d"
[[2]]
[1] "a" "c" "d"
[[3]]
[1] "a" "b" "d"
[[4]]
[1] "a" "b" "c"
I found it hard to formulate the question but I would like to find a clever way (not using loop) to get the following result:
> my.vector = letters[1:6]
> print(my.vector)
[1] "a" "b" "c" "d" "e" "f"
>
> my.list = (rep(list(NA),6))
> for (i in 1:length(my.vector)){
+ x = my.vector[1:i]
+ my.list[[i]] = x
+ }
> print(my.list)
[[1]]
[1] "a"
[[2]]
[1] "a" "b"
[[3]]
[1] "a" "b" "c"
[[4]]
[1] "a" "b" "c" "d"
[[5]]
[1] "a" "b" "c" "d" "e"
[[6]]
[1] "a" "b" "c" "d" "e" "f"
Thanks in advance,
Gabriel.
You can do:
lapply(seq_along(my.vector), head, x = my.vector)
Here's an approach (more verbose than #akrun's, but not dependent on the actual values in the original vector).
split(my.vector[sequence(seq_along(my.vector))],
rep(seq_along(my.vector), seq_along(my.vector)))
## $`1`
## [1] "a"
##
## $`2`
## [1] "a" "b"
##
## $`3`
## [1] "a" "b" "c"
##
## $`4`
## [1] "a" "b" "c" "d"
##
## $`5`
## [1] "a" "b" "c" "d" "e"
##
## $`6`
## [1] "a" "b" "c" "d" "e" "f"
##
If you wanted a matrix instead of a list, you can try:
> x <- t(replicate(length(my.vector), my.vector))
> x[upper.tri(x)] <- ""
> x
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] "a" "" "" "" "" ""
[2,] "a" "b" "" "" "" ""
[3,] "a" "b" "c" "" "" ""
[4,] "a" "b" "c" "d" "" ""
[5,] "a" "b" "c" "d" "e" ""
[6,] "a" "b" "c" "d" "e" "f"
We can use
v1 <- my.vector[sequence(seq_along(my.vector))]
split(v1, cumsum(v1=='a'))