Generazione di tutte le permutazioni distinte di un elenco in R

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])