在R语言中生成无重复“非随机”数字的实现方案求助
解决你的「不完全随机」无重复序列生成问题
嘿,先帮你梳理下现有代码里的几个关键问题,这也是你报错和逻辑走不通的原因:
sample.int(1, 100, replace = FALSE)参数搞反啦!sample.int的语法是sample.int(n, size),你想从100个数字里选1个,应该写成sample.int(100, 1, replace=FALSE),反过来就会触发"样本不能大于总体"的错误,这正是你遇到的问题。- 变量初始化太混乱:比如
guess_sets_i还没赋值就直接用setdiff,第一次循环时guess_i都没定义就想guess_i +1,还有all_games_i的as.list用法错了(应该用list(index_i, guess_i, ...)而不是as.list传多参数)。 - 没处理你提到的边界情况:比如当前数字是100时不能加1,或者前一个数字加1后已经被用过的情况。
接下来给你正确的实现方式,我把单个序列的生成封装成了函数,这样逻辑清晰,也方便重复生成100次:
第一步:编写单个序列生成函数
这个函数严格遵循你的规则:第一个数字随机选,之后每个数字有50%概率是前一个+1(前提是+1后不超范围且未被使用),否则随机选未用过的数字:
generate_semi_random_seq <- function(max_num = 100) { # 初始化已使用数字集合和结果序列 used <- integer(0) seq <- integer(0) # 第一个数字随机选取 first_num <- sample.int(max_num, 1) seq <- c(seq, first_num) used <- c(used, first_num) # 生成剩下的99个数字 for (i in 2:max_num) { prev_num <- seq[i-1] # 50%概率尝试前一个数字+1 if (runif(1) > 0.5) { next_candidate <- prev_num + 1 # 检查候选数字是否合法(在范围内且未被使用) if (next_candidate <= max_num && !(next_candidate %in% used)) { seq <- c(seq, next_candidate) used <- c(used, next_candidate) next # 合法的话直接进入下一次循环,跳过随机选择 } } # 如果加1不合法,就从剩余未使用的数字里随机选一个 available <- setdiff(1:max_num, used) next_num <- sample(available, 1) seq <- c(seq, next_num) used <- c(used, next_num) } return(seq) }
第二步:生成100个这样的序列
用replicate可以非常简便地生成多个序列,比手动循环列表清爽多了:
# 生成100个序列,每个序列是一个向量,存储在列表中 all_games <- replicate(100, generate_semi_random_seq(), simplify = FALSE) # 如果想转成数据框(每一行对应一个序列),可以这么做: all_games_df <- do.call(rbind, lapply(all_games, function(x) data.frame(t(x)))) # 给列命名(可选操作) colnames(all_games_df) <- paste0("num_", 1:100)
看看示例结果
运行generate_semi_random_seq(),你会得到类似这样的序列:
[1] 5 6 51 4 3 88 87 9 10 11 12 ...(后续是剩余未使用的数字)
完全符合你想要的格式~
有没有更简便的写法?
上面的方法已经很清晰易读了,如果想优化效率(比如生成更大的序列),可以用集合来存储已使用的数字,查找速度会更快。比如用sets包的set类型:
# 先安装sets包(如果没装的话) # install.packages("sets") library(sets) generate_semi_random_seq_fast <- function(max_num = 100) { used <- set() seq <- integer(0) first_num <- sample.int(max_num, 1) seq <- c(seq, first_num) used <- used + first_num for (i in 2:max_num) { prev_num <- seq[i-1] if (runif(1) > 0.5) { next_candidate <- prev_num + 1 if (next_candidate <= max_num && !(next_candidate %in% used)) { seq <- c(seq, next_candidate) used <- used + next_candidate next } } available <- setdiff(1:max_num, as.vector(used)) next_num <- sample(available, 1) seq <- c(seq, next_num) used <- used + next_num } return(seq) }
不过对于100个数字的场景,用普通向量存储已使用数字完全够用,没必要特意装包。
总的来说,你的核心思路非常棒,只需要修正代码里的参数错误和变量初始化问题,再补充边界条件的检查,就能完美实现你想要的「不完全随机」序列啦!
内容的提问来源于stack exchange,提问作者stats_noob
相关产品推荐
相关产品推荐

