2012-06-19 15 views
31

Estoy tratando de crear una lista de permutaciones de una lista, de manera que, por ejemplo, perms(list("a", "b", "c")) vuelveGeneración de todas las permutaciones distintas de una lista en I

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

no estoy seguro de cómo proceder, cualquier ayuda sería muy apreciada.

+0

Hay varios paquetes para generar permutaciones en R. Escribí una ** [Resumen] (https://stackoverflow.com/a/47983855/4408538) ** que incluye puntos de referencia, así como demostraciones de uso para cada método disponible. –

Respuesta

35

combinat::permn hará ese trabajo:

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

Tenga en cuenta que el cálculo es enorme si el elemento es grande.

24

Usted puede intentar permutations() del paquete gtools, pero a diferencia de permn()combinat, que no da salida a una lista:

> 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

Merece señalar que 'permutations' es más flexible. Permite la permutación de m de n elementos y permite el uso repetido de elementos. Lo encontré después de probar 'permn' sin éxito. – mt1022

20

base de R también puede proporcionar la respuesta:

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

Un mientras que atrás tenía que hacer esto en la base R sin cargar ningún paquete.

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

Buena función. Parece bastante rápido también. – A5C1D2H2I1M1N2O1R2T1

7

Probar:

> 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 

Como sugiere @Adrian en los comentarios, última línea se puede sustituir por:

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

o, para la última línea: 'p. Ej. [Aplicar (p. Ej., 1, cualquier duplicado) == 0,]' – Adrian

+0

Buena sugerencia. – rnso

+0

@dusadrian Una nota sobre escalabilidad: lo pensaría dos veces antes de usar este enfoque en código "serio", ya que el espacio buscado (p. Ej.) Crece excesivamente grande a medida que aumenta el tamaño de muestra/conjunto muestreado (tasa de acierto: n! Vs. n^n - empeora casi estimado exponencialmente a partir de la fórmula de Stirling). En el caso de 10 de 10, la proporción de aciertos solo es 'prod (1:10)/(10^10) = 0.036%'. Y parece que todas las variantes examinadas se almacenan en algún momento en la memoria, en un marco de datos. Sin embargo, siempre me gustó este para pequeñas tareas manuales, ya que es muy fácil de entender. – 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 solución divertida "probabilística" por medio de la muestra para 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 

básicamente se llaman muchas muestras al azar, con la esperanza de llegar a todos ellos, y que sean únicos.

7

Una solución de la base de R, sin dependencias de otros paquetes:

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

espero que esto ayude.

+1

Supera la solución 'gtools'. – snoram

+0

No lo he probado antes, pero parece que sí. Guay. – Adrian

0

¿Qué hay de

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[.]) }

Esto da una lista. Entonces

pmsa(letters[1:3])

Cuestiones relacionadas