2012-06-19 10 views
31

Sto cercando di creare un elenco di permutazioni di una lista, in modo tale che, ad esempio, i rendimenti perms(list("a", "b", "c"))Generazione di tutte le permutazioni distinte di una lista in R

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.

+0

Ci sono diversi pacchetti per la generazione di permutazioni in R. ho scritto un ** [sintesi] (https://stackoverflow.com/a/47983855/4408538) ** che include parametri di riferimento, così come dimostrazioni di utilizzo per ogni metodo disponibile. –

risposta

35

combinat::permn farà quel 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.

24

Si può provare permutations() dal pacchetto gtools, ma a differenza di permn() da combinat, esso non emette 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" 
+2

Va notato che 'permutations' è più flessibile. Permette di permutare m di n elementi e permettere un uso ripetuto di elementi. L'ho trovato dopo aver provato "permn" senza successo. – mt1022

20

base di 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}),] 
31

A mentre tornavo dovevo 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) 
    } 
} 

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" 
+2

Funzione piacevole. Sembra anche abbastanza veloce. – A5C1D2H2I1M1N2O1R2T1

7

Prova:

> 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 

Come suggerito da @Adrian nei commenti, nell'ultima riga può essere sostituito da:

eg[apply(eg, 1, anyDuplicated) == 0, ] 
+0

o, per l'ultima riga: 'eg [applica (es. 1, anyDuplicated) == 0,]' – Adrian

+0

Buon suggerimento. – rnso

+0

@dusadrian Una nota sulla scalabilità: ci penserei due volte prima di utilizzare questo approccio nel codice "serio", poiché lo spazio cercato (ad es.) Cresce irragionevolmente enorme all'aumentare della dimensione del campione/dell'insieme campionato (velocità di hit: n! Vs. n^n - peggiora approssimativamente esponenzialmente stimato dalla formula di Stirling). Per il caso 10 su 10, il rapporto di hit è solo 'prod (1:10)/(10^10) = 0.036%' già. E sembra che tutte quelle varianti esaminate siano a un certo punto memorizzate, in un frame di dati. Tuttavia, mi è sempre piaciuto questo per le piccole attività manuali in quanto è così facile da capire. – brezniczky

8
# 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" 
3

Una soluzione divertente "probabilistica" utilizzando 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 

fondamentalmente si chiamano molti campioni casuali, sperando di farli tutti, e li unici.

7

una soluzione in base di R, senza dipendenze 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 questo aiuta.

+1

Soddisfa la soluzione 'gtools'. – snoram

+0

Non ho provato prima, ma sembra così. Freddo. – Adrian

0

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

Problemi correlati