以6种不同的方式列出3个数字的组合?

时间:2018-12-23 00:41:25

标签: r permutation

我希望能够构造一个从001到999的数字范围,其中从001到199的函数将以多达6种不同的方式列出数字的组合。示例192为192、129、291、219、912、921。列表显然应该以001开头,它将显示为:001、010、100。

3 个答案:

答案 0 :(得分:1)

我不确定您想要哪种格式的结果。

如前所述,这些是排列:combinat::permn可能是实现此目的的最方便的方法。

使用零填充("%03d")格式化数字,并分割成字符(strsplit(.,"")):

f0 <- function(x) strsplit(sprintf("%03d",x),"")[[1]]

创建所有排列,将它们压回字符串(paste/collapse),然后选择唯一值(例如000仅具有一个唯一值)

f1 <- function(x) unique(sapply(combinat::permn(f0(x)),paste,collapse=""))

适用于每个整数

result <- lapply(0:999,f1)

head(result)
[[1]]
[1] "000"

[[2]]
[1] "001" "010" "100"

[[3]]
[1] "002" "020" "200"

[[4]]
[1] "003" "030" "300"

[[5]]
[1] "004" "040" "400"

[[6]]
[1] "005" "050" "500"

后来的值确实有多达六个条目。

答案 1 :(得分:1)

您可以使用tidyr::crossingexpand.grid来创建索引向量:

library(tidyverse)

indices <- crossing(x = 1:3, y = 1:3, z = 1:3) %>% 
    filter(x != y, x != z, y != z) %>% 
    pmap(~unname(c(...)))

indices %>% str
#> List of 6
#>  $ : int [1:3] 1 2 3
#>  $ : int [1:3] 1 3 2
#>  $ : int [1:3] 2 1 3
#>  $ : int [1:3] 2 3 1
#>  $ : int [1:3] 3 1 2
#>  $ : int [1:3] 3 2 1

...,然后在遍历所有输入向量时可以用来对它们进行子集化:

perms <- pmap(crossing(x = 0:9, y = 0:9, z = 0:9), function(...){
    map_chr(indices, function(x) paste(c(...)[x], collapse = "")) %>% 
        unique()
})

perms[500:510] %>% str(vec.len = 6)
#> List of 11
#>  $ : chr [1:3] "499" "949" "994"
#>  $ : chr [1:3] "500" "050" "005"
#>  $ : chr [1:6] "501" "510" "051" "015" "150" "105"
#>  $ : chr [1:6] "502" "520" "052" "025" "250" "205"
#>  $ : chr [1:6] "503" "530" "053" "035" "350" "305"
#>  $ : chr [1:6] "504" "540" "054" "045" "450" "405"
#>  $ : chr [1:3] "505" "550" "055"
#>  $ : chr [1:6] "506" "560" "056" "065" "650" "605"
#>  $ : chr [1:6] "507" "570" "057" "075" "750" "705"
#>  $ : chr [1:6] "508" "580" "058" "085" "850" "805"
#>  $ : chr [1:6] "509" "590" "059" "095" "950" "905"

这最终仍然是很多迭代,因此尽管它可以进行6000次迭代足够快,但矢量化方法会更好地扩展。

答案 2 :(得分:0)

这里是一种解决方案,可以在不重复的情况下提供所需的输出,并且无需其他调用即可清除重复的结果。我们利用std::next_permutation中算法库中的C++来利用001,该算法库将向量作为输入并生成字典编排,直到达到第一个排列。这意味着,我们仅为999生成3个排列,为123生成1个排列,为as.character(0:9)生成6个排列。

我们首先利用gtools::combinations生成长度为3的## install.packages("gtools") myCombs <- gtools::combinations(10, 3, as.character(0:9), repeats.allowed = TRUE) nrow(myCombs) [1] 220 的所有组合,并进行重复。

Rcpp

这里是一个std::next_permutation版本,将R暴露给## install.packages("Rcpp") Rcpp::cppFunction( "CharacterVector permuteDigits(CharacterVector v) { std::string myStr; std::vector<std::string> result; for (std::size_t i = 0; i < v.size(); ++i) myStr += v[i]; do { result.push_back(myStr); } while(std::next_permutation(myStr.begin(), myStr.end())); return wrap(result); }" )

lapply

最后,我们将其与permutedCombs <- lapply(1:nrow(myCombs), function(x) { permuteDigits(myCombs[x, ]) }) 一起使用:

permutedCombs[1:5]
[[1]]
[1] "000"

[[2]]
[1] "001" "010" "100"

[[3]]
[1] "002" "020" "200"

[[4]]
[1] "003" "030" "300"

[[5]]
[1] "004" "040" "400"

permutedCombs[151:155]
[[1]]
[1] "356" "365" "536" "563" "635" "653"

[[2]]
[1] "357" "375" "537" "573" "735" "753"

[[3]]
[1] "358" "385" "538" "583" "835" "853"

[[4]]
[1] "359" "395" "539" "593" "935" "953"

[[5]]
[1] "366" "636" "663"

以下是一些示例输出:

sum(lengths(permutedCombs))
[1] 1000

identical(sort(as.integer(do.call(c, permutedCombs))), 0:999)
[1] TRUE

这证明我们有1000个结果,没有重复:

{{1}}