Sto cercando di creare un elenco di permutazioni di un elenco, in modo tale che, ad esempio, i perms(list("a", "b", "c"))
restituiscano
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"))
Non sono sicuro di come procedere, qualsiasi aiuto sarebbe molto apprezzato.
combinat::permn
farà questo lavoro:
> 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"
Nota che il calcolo è enorme se l’elemento è grande.
Qualche tempo fa ho dovuto farlo nella base R senza caricare alcun pacchetto.
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) } }
Uso:
> 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"
Puoi provare permutations()
dal pacchetto gtools
, ma a differenza di permn()
da combinat
, non restituisce un elenco:
> 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"
la base R può anche fornire la risposta:
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}),]
# 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"
Una soluzione in R base, nessuna dipendenza da altri pacchetti:
> getPerms <- 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) } } > getPerms(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"
Spero che aiuti.
Provare:
> 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 cba 8 bca 12 cab 16 acb 20 bac 22 abc
Come suggerito da @Adrian nei commenti, l’ultima riga può essere sostituita da:
eg[apply(eg, 1, anyDuplicated) == 0, ]
Una soluzione divertente “probabilistica” utilizzando il campione per la 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
in pratica chiamate molti campioni casuali, sperando di averli tutti, e li avete unici.
Che dire
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[.]) }
Questo dà una lista. Poi
pmsa(letters[1:3])