生成 R 中列表的所有不同排列

问题描述 投票:0回答:14

我正在尝试创建列表的排列列表,例如,

perms(list("a", "b", "c"))
返回

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

我不知道如何继续,任何帮助将不胜感激。

r permutation
14个回答
65
投票

不久前,我不得不在 R 基础上执行此操作,而不加载任何包。

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

用途:

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

63
投票

combinat::permn
将完成这项工作:

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

请注意,如果元素很大,计算量会很大。


38
投票

base R 也可以提供答案:

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

37
投票

您可以尝试

permutations()
包中的
gtools
,但与
permn()
中的
combinat
不同,它不会输出列表:

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

20
投票

基础 R 中的解决方案,不依赖于其他包:

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

我希望这有帮助。


12
投票

尝试:

> 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

根据@Adrian 在评论中的建议,最后一行可以替换为:

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

11
投票
# 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" 

5
投票

使用样本作为基础 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

基本上,您会调用许多随机样本,希望获得全部样本,并且您将它们独一无二。


3
投票

看哪,

purrr
🐾解决方案:

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

2
投票

如果这有帮助,有“安排”包,可以让您简单地做:

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

2
投票

我们可以使用基函数
combn
,稍作修改:

   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"   


0
投票

rnso 的答案的通用版本是:

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, ] }
这里有两个例子:

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"
还可以通过使用 

lapply 稍微改变 Rick 的答案

,只执行一次 
rbind
,并减少 
[s]/[l]apply
 调用的次数:

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

0
投票
使用

RcppAlgos::permuteGeneral


> v <- letters[1:3] > > RcppAlgos::permuteGeneral(v) [,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"

> lapply(seq_along(v), \(m) RcppAlgos::permuteGeneral(v, m)) [[1]] [,1] [1,] "a" [2,] "b" [3,] "c" [[2]] [,1] [,2] [1,] "a" "b" [2,] "a" "c" [3,] "b" "a" [4,] "b" "c" [5,] "c" "a" [6,] "c" "b" [[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"
    

-1
投票
那又如何

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

这给出了一个列表。然后

pmsa(letters[1:3])


    

© www.soinside.com 2019 - 2024. All rights reserved.