我试图用数字创建20张独特的牌,但我有点挣扎..所以基本上我需要创建20个独特的矩阵3x3,第一列中的数字为1-10,第二列中的数字为11-20列和第三列中的21-30 ..任何想法?我更喜欢在r中完成它,特别是因为我不了解Visual Basic。在Excel中我知道如何生成卡片,但不知道如何确保它们是独一无二的。
对我来说,它似乎非常精确和直接。无论如何,我需要创建20个矩阵,如下所示:
[,1] [,2] [,3]
[1,] 5 17 23
[2,] 8 18 22
[3,] 3 16 24
每个矩阵应该是唯一的,每个列应该由三个唯一的数字组成(第1列 - 数字1-10,第2列11-20,第3列 - 21-30)。
生成随机数很容易,但如何确保生成的卡片是唯一的?请查看我投票的帖子作为答案 - 因为它为您提供了如何实现它的全面解释。
答案 0 :(得分:1)
(注意:我误读了“行”而不是“列”,所以下面的代码和解释将处理第1行的随机数1-10,第2行的11-20等矩阵。列,但它只是转置完全相同)
此代码应保证唯一性和良好的随机性:
library(gtools)
# helper function
getKthPermWithRep <- function(k,n,r){
k <- k - 1
if(n^r< k){
stop('k is greater than possibile permutations')
}
v <- rep.int(0,r)
index <- length(v)
while ( k != 0 )
{
remainder<- k %% n
k <- k %/% n
v[index] <- remainder
index <- index - 1
}
return(v+1)
}
# get all possible permutations of 10 elements taken 3 at a time
# (singlerowperms = 720)
allperms <- permutations(10,3)
singlerowperms <- nrow(allperms)
# get 20 random and unique bingo cards
cards <- lapply(sample.int(singlerowperms^3,20),FUN=function(k){
perm2use <- getKthPermWithRep(k,singlerowperms,3)
m <- allperms[perm2use,]
m[2,] <- m[2,] + 10
m[3,] <- m[3,] + 20
return(m)
# if you want transpose the result just do:
# return(t(m))
})
(免责声明tl; dr)
为了保证随机性和唯一性,一种安全的方法是生成所有可能的宾果卡,然后在其中随机选择而无需替换。
要生成所有可能的卡片,我们应该:
使用包permutations
的函数gtools
可以轻松获得步骤(1)(请参阅代码中的对象allPerms
)。注意,我们只需要第一行的排列(即从1-10中取出的3个元素),因为通过分别加10和20可以容易地从第一行获得其他行的排列。
步骤(2)也很容易进入R,但我们首先考虑将产生多少种可能性。步骤(1)每行返回720个案例,最后我们将有720*720*720 = 720^3 = 373248000
个可能的宾果卡!
生成所有这些都是不实际的,因为占用的内存将是巨大的,因此我们需要找到一种方法来在这种大范围的可能性中获得20个随机元素,而不实际将它们保存在内存中。
解决方案来自函数getKthPermWithRep
,在给定索引k
的情况下,它返回第k个排列,重复r
元素取自1:n
(请注意,在这种情况下,重复排列对应于笛卡尔积。)
e.g。
# all permutations with repetition of 2 elements in 1:3 are
permutations(n = 3, r = 2,repeats.allowed = TRUE)
# [,1] [,2]
# [1,] 1 1
# [2,] 1 2
# [3,] 1 3
# [4,] 2 1
# [5,] 2 2
# [6,] 2 3
# [7,] 3 1
# [8,] 3 2
# [9,] 3 3
# using the getKthPermWithRep you can get directly the k-th permutation you want :
getKthPermWithRep(k=4,n=3,r=2)
# [1] 2 1
getKthPermWithRep(k=8,n=3,r=2)
# [1] 3 2
因此,现在我们只选择1:720^3
范围内的20个随机索引(使用sample.int
函数),然后对于每个索引,我们得到从1:720
取得的3个数字的相应排列功能getKthPermWithRep
。
最后,这些数字的三元组可以转换为实际的卡行,方法是将它们用作子集allPerms
的索引并获取最终矩阵(当然,之后将+10
和+20
添加到第2和第3行)。
如果你看一下上面的例子(在1:3中重复2个元素的排列),然后将1减去所有结果,你得到这个:
> permutations(n = 3, r = 2,repeats.allowed = T) - 1
[,1] [,2]
[1,] 0 0
[2,] 0 1
[3,] 0 2
[4,] 1 0
[5,] 1 1
[6,] 1 2
[7,] 2 0
[8,] 2 1
[9,] 2 2
如果您将每行的每个数字视为数字,您可以注意到那些行(00,01,02 ...)都是0到8之间的数字,以3为基数表示(是的,3为N)。因此,当您在r
中重复1:n
元素时询问第k个排列时,您还要求将k-1
翻译为基数n
并返回增加的数字1
。
因此,给定算法将任何数字从基数10改为基数n:
changeBase <- function(num,base){
v <- NULL
while ( num != 0 )
{
remainder = num %% base # assume K > 1
num = num %/% base # integer division
v <- c(remainder,v)
}
if(is.null(v)){
return(0)
}
return(v)
}
您可以轻松获得getKthPermWithRep
功能。
答案 1 :(得分:0)
可以使用以下代码生成一个具有所需值范围的3x3矩阵:
mat <- matrix(c(sample(1:10,3), sample(11:20,3), sample(21:30, 3)), nrow=3)
此外,您可以使用for循环生成20个唯一矩阵的列表,如下所示:
for (i in 1:20) {
mat[[i]] <- list(matrix(c(sample(1:10,3), sample(11:20,3), sample(21:30,3)), nrow=3))
print(mat[[i]])
}
答案 2 :(得分:0)
好吧,我可能会在这里摔倒,但我建议使用校验和(使用Excel)。
这是每个宾果卡的唯一签名,如果在不更改实际数字的情况下更改任何列中的数字顺序,它将保持不变。公式是
=SUM(10^MOD(A2:A4,10)+2*10^MOD(B2:B4,10)+4*10^MOD(C2:C4,10))
第一张牌的宾果号码在A2:C4。
我们的想法是为每列生成一个10位数的数字,然后将每个数字乘以一个常数并添加它们以获得签名。
所以我在这里使用here加上两个标准公式生成了两张随机宾果卡,故意将它们作为彼此的排列。
然后我使用公式
检查是否有任何签名是重复的=MAX(COUNTIF(D5:D20,D5:D20))
不应该给出超过1的答案。
如果有重复的话,你只需按F9并生成一些新卡。
所有公式都是数组公式,必须使用 Ctrl Shift 输入
输入答案 3 :(得分:0)
这是一种不太优雅的方式。生成所有可能的组合,然后无需更换即可进行采样这些是排列,组合:订单在宾果游戏中很重要
library(dplyr)
library(tidyr)
library(magrittr)
generate_samples = function(n) {
first = data_frame(first = (n-9):n)
first %>%
merge(first %>% rename(second = first)) %>%
merge(first %>% rename(third = first)) %>%
sample_n(20)
}
suffix = function(df, suffix)
df %>%
setNames(names(.) %>%
paste0(suffix))
generate_samples(10) %>% suffix(10) %>%
bind_cols(generate_samples(20) %>% suffix(20)) %>%
bind_cols(generate_samples(30) %>% suffix(30)) %>%
rowwise %>%
do(matrix = t(.) %>% matrix(3)) %>%
use_series(matrix)