在R中检测数字集合能否求和至指定值的标准方法问询
问题描述
我有如下数据框:
set.seed(123) random_table <- data.frame( Column1 = sample(1:10, 5, replace = TRUE), Column2 = sample(1:10, 5, replace = TRUE), Column3 = sample(1:10, 5, replace = TRUE), Column4 = sample(1:10, 5, replace = TRUE), Column5 = sample(1:10, 5, replace = TRUE) )
数据框内容:
Column1 Column2 Column3 Column4 Column5 3 5 5 3 9 3 4 3 8 3 10 6 9 10 4 2 9 9 7 1 6 10 9 10 7
我希望编写一个函数,检测该数据框中选取n个数字能否求和得到指定值m,若可行则记录所有符合条件的组合(包含对应单元格位置),否则返回NULL。
我尝试使用combinat包编写了如下函数:
library(combinat) find_combinations <- function(table, num, target_sum) { combinations <- combn(as.vector(as.matrix(table)), num) valid_combinations <- list() valid_cells <- list() for (i in 1:ncol(combinations)) { if (sum(combinations[, i]) == target_sum) { valid_combinations <- append(valid_combinations, list(combinations[, i])) cells <- c() for (value in combinations[, i]) { cell <- which(table == value, arr.ind = TRUE)[1, ] cells <- c(cells, paste0(LETTERS[cell[2]], cell[1])) } valid_cells <- append(valid_cells, list(cells)) } } if (length(valid_combinations) > 0) { result <- data.frame( id = seq_along(valid_combinations), sum = rep(target_sum, length(valid_combinations)), numbers_selected = sapply(valid_combinations, function(x) paste(x, collapse = ",")), cells = sapply(valid_cells, function(x) paste(x, collapse = ",")) ) } else { result <- data.frame( id = NA, sum = NA, numbers_selected = NA, cells = NA ) } return(result) }
随后我调用该函数并移除了cells列相关的重复项:
result <- find_combinations(random_table, num = 4, target_sum = 19) result$sorted_cells <- sapply(strsplit(result$cells, ","), function(x) paste(sort(x), collapse = ",")) result <- result[!duplicated(result$sorted_cells), ] result$sorted_cells <- NULL result$id <- seq_len(nrow(result))
输出结果如下:
id sum numbers_selected cells 1 19 3,3,10,3 A1,A1,A3,A1 2 19 3,3,6,7 A1,A1,A5,D4 3 19 3,3,5,8 A1,A1,B1,D2 4 19 3,3,4,9 A1,A1,B2,B4 5 19 3,10,2,4 A1,A3,A4,B2
请问在R中是否有实现该需求的标准方法,还是必须自行编写函数?
解答
在R里没有完全直接匹配这个需求的「标准函数」,但可以借助现有工具包简化实现,同时优化你当前代码里的问题(比如原代码中which(table == value, arr.ind = TRUE)[1, ]只会取第一个匹配值,会丢失其他可能的单元格位置,导致组合记录不全)。
优化思路与实现
- 先转长格式追踪位置:把数据框转换成包含值、行号、列名的长表,避免重复值导致的位置匹配错误。
- 基于位置生成组合:直接对每个元素的位置做组合筛选,再匹配对应的值求和,确保位置记录准确。
- 高效去重:直接基于排序后的位置组合去重,不用额外生成中间列。
示例优化代码:
find_combinations <- function(df, num, target_sum) { # 转换为长格式,记录每个值的单元格位置 long_df <- data.frame( value = unlist(df), cell = paste0(LETTERS[col(df)], row(df)), stringsAsFactors = FALSE ) # 生成所有num个元素的位置组合 pos_combinations <- combn(1:nrow(long_df), num) # 筛选求和等于目标值的组合 valid_idx <- apply(pos_combinations, 2, function(idx) sum(long_df$value[idx]) == target_sum) valid_pos <- pos_combinations[, valid_idx, drop = FALSE] if (ncol(valid_pos) == 0) { return(NULL) } # 整理结果并去重 result_list <- apply(valid_pos, 2, function(idx) { cells <- long_df$cell[idx] sorted_cells <- sort(cells) list( sum = target_sum, numbers_selected = paste(long_df$value[idx], collapse = ","), cells = paste(cells, collapse = ","), sorted_cells = paste(sorted_cells, collapse = ",") ) }) result_df <- do.call(rbind.data.frame, result_list) # 去重并清理列 result_df <- result_df[!duplicated(result_df$sorted_cells), ] result_df$sorted_cells <- NULL result_df$id <- seq_len(nrow(result_df)) # 调整列顺序 result_df <- result_df[, c("id", "sum", "numbers_selected", "cells")] return(result_df) } # 调用测试 result <- find_combinations(random_table, num = 4, target_sum = 19) print(result)
可选工具包支持
- 处理大数据量时,
arrangements包的combinations函数比combinat包的combn性能更优; - 若只需判断是否存在解而非枚举所有组合,可以用
lpSolve包做整数规划求解; - 追求极致效率的话,可结合
Rcpp编写底层逻辑加速组合筛选。
内容的提问来源于stack exchange,提问作者farrow90
相关产品推荐
相关产品推荐

