代码之家  ›  专栏  ›  技术社区  ›  Zheyuan Li

不同集合的混合组合/排列

  •  2
  • Zheyuan Li  · 技术社区  · 6 年前

    How to build permutation with some conditions in R

    到目前为止,已经有一些好的R包,比如 RcppAlgos arrangements 提供有效的组合/排列 在一套设备上 . 例如,如果我们想从中选择3个项目,下面给出了所有的组合 letters[1:6] :

    library(RcppAlgos)
    comboGeneral(letters[1:6], 3)
    #      [,1] [,2] [,3]
    # [1,] "a"  "b"  "c" 
    # [2,] "a"  "b"  "d" 
    # [3,] "a"  "b"  "e" 
    # [4,] "a"  "b"  "f" 
    # [5,] "a"  "c"  "d" 
    # [6,] "a"  "c"  "e" 
    # [7,] "a"  "c"  "f" 
    # [8,] "a"  "d"  "e" 
    # [9,] "a"  "d"  "f" 
    #[10,] "a"  "e"  "f" 
    #[11,] "b"  "c"  "d" 
    #[12,] "b"  "c"  "e" 
    #[13,] "b"  "c"  "f" 
    #[14,] "b"  "d"  "e" 
    #[15,] "b"  "d"  "f" 
    #[16,] "b"  "e"  "f" 
    #[17,] "c"  "d"  "e" 
    #[18,] "c"  "d"  "f" 
    #[19,] "c"  "e"  "f" 
    #[20,] "d"  "e"  "f" 
    

    • 从中选择1项 LETTERS[1:2]
    • 从中选择3项 字母[1:6]
    • as.character(1:3)

    如何生成所有组合和可选的所有排列?

    1 回复  |  直到 6 年前
        1
  •  3
  •   Zheyuan Li    6 年前

    假设我们有一个集合列表 set_list ,在哪里 k[i] 项目从中选择 set_list[[i]] ,那么从数学上讲,我们可以这样来解决这个问题:

    1. 生成每个集合的所有组合;
    2. 为每个组合创建所有排列。

    函数 MixedCombnPerm RcppAlgos 对于第1步和第3步。目前第2步没有使用最优算法。它是一种“野蛮的力量”,依赖于更快地执行法律 expand.grid rbind mgcv )这可以在Rcpp中进行编码,但由于时间原因,我现在不会这么做。

    library(RcppAlgos)
    
    MixedCombnPerm <- function (set_list, k, perm = FALSE) {
    
      ###################
      ## mode checking ##
      ###################
    
      if (!all(vapply(set_list, is.vector, TRUE)))
        stop("All sets must be 'vectors'!")
    
      if (length(unique(vapply(set_list, mode, ""))) > 1L)
        stop("Please ensure that all sets have the same mode!")
    
      ################
      ## basic math ##
      ################
    
      ## size of each sets
      n <- lengths(set_list, FALSE)
      ## input validation
      if (length(n) != length(k)) stop("length of 'k' different from number of sets!")
      if (any(k > n)) stop("can't choose more items than set size!")
      ## number of sets
      n_sets <- length(n)
      ## total number of items
      n_items <- sum(k)
      ## number of combinations
      n_combinations_by_set <- choose(n, k)
      n_combinations <- prod(n_combinations_by_set)
    
      #################################
      ## step 1: combinations by set ##
      #################################
    
      ## generate `n_combinations[i]` combinations on set i
      combinations_by_set <- vector("list", n_sets)
      for (i in seq_len(n_sets)) {
        ## each column of combinations_by_set[[i]] is a record
        combinations_by_set[[i]] <- t.default(comboGeneral(set_list[[i]], k[i]))
        }
    
      ################################
      ## step 2: merge combinations ##
      ################################
    
      ## merge combinations from all sets
      ## slow_expand_grid <- function (m) expand.grid(lapply(m, seq_len))
      fast_expand_grid <- function (m) {
        n_sets <- length(m)      ## number of sets
        mm <- c(1L, cumprod(m))  ## cumulative leading dimension
        grid_size <- mm[n_sets + 1L]  ## size of the grid
        grid_ind <- vector("list", n_sets)
        for (i in seq_len(n_sets)) {
          ## grid_ind[[i]] <- rep_len(rep(seq_len(m[i]), each = mm[i]), M)
          grid_ind[[i]] <- rep_len(rep.int(seq_len(m[i]), rep.int(mm[i], m[i])), grid_size)
          }
        grid_ind
        }
      grid_ind <- fast_expand_grid(n_combinations_by_set)
    
      ## each column is a record
      combinations_grid <- mapply(function (x, j) x[, j, drop = FALSE],
                           combinations_by_set, grid_ind,
                           SIMPLIFY = FALSE, USE.NAMES = FALSE)
      all_combinations <- do.call("rbind", combinations_grid)
    
      ########################################################
      ## step 3: generate permutations for each combination ##
      ########################################################
    
      if (!perm) return(all_combinations)
      else {
        ## generate `factorial(n_items)` permutations for each combination
        all_permutations <- vector("list", n_combinations)
        for (i in seq_len(n_combinations)) {
          all_permutations[[i]] <- permuteGeneral(all_combinations[, i], n_items)
          }
        return(all_permutations)
        }
    
      }
    

    ## note the "as.character(1:3)"
    set_list <- list(LETTERS[1:2], letters[1:6], as.character(1:3))
    k <- c(1, 3, 2)
    

    函数返回矩阵中的组合(每列都是一条记录)if参数 perm = FALSE

    请尝试以下示例:

    combinations <- MixedCombnPerm(set_list, k)
    permutations <- MixedCombnPerm(set_list, k, TRUE)
    

    combinations[, 1:6]
    #     [,1] [,2] [,3] [,4] [,5] [,6]
    #[1,] "A"  "B"  "A"  "B"  "A"  "B" 
    #[2,] "a"  "a"  "a"  "a"  "a"  "a" 
    #[3,] "b"  "b"  "b"  "b"  "b"  "b" 
    #[4,] "c"  "c"  "d"  "d"  "e"  "e" 
    #[5,] "1"  "1"  "1"  "1"  "1"  "1" 
    #[6,] "2"  "2"  "2"  "2"  "2"  "2" 
    
    permutations[[1]][1:6, ]
    #     [,1] [,2] [,3] [,4] [,5] [,6]
    #[1,] "A"  "a"  "b"  "c"  "1"  "2" 
    #[2,] "A"  "a"  "b"  "c"  "2"  "1" 
    #[3,] "A"  "a"  "b"  "1"  "c"  "2" 
    #[4,] "A"  "a"  "b"  "1"  "2"  "c" 
    #[5,] "A"  "a"  "b"  "2"  "c"  "1" 
    #[6,] "A"  "a"  "b"  "2"  "1"  "c"