列出 6 位数字中的所有 3 位数字组合
List all 3 digit combinations out of 6 digits
假设我有 6 个号码:
a <- c(1,2,3,4,5,6)
我想列出这 6 个数字的所有可能的 3 位组合,包括重复。
期望的结果如下所示:
1 1 1
1 2 3
1 2 4
...
我不想包含具有相同 3 个数字但顺序不同的元素:
例如
1 2 3
3 2 1
应排除其中之一
一个简单的方法是使用三个 for 循环。这个结果是你想要的吗?
for (x in 1:6) {
for (y in x:6) {
for (z in y:6) {
print(paste(x,y,z))
}
}
}
gtools
中的 combinations
函数可以做到这一点:
library(gtools)
combinations(n=6, r=3, v=a, repeats.allowed=TRUE)
[,1] [,2] [,3]
[1,] 1 1 1
[2,] 1 1 2
[3,] 1 1 3
...
[54,] 5 5 6
[55,] 5 6 6
[56,] 6 6 6
expand.grid
returns 一个 data.frame 的组合,从你提供的每一组中挑选一个。如果 1 2 3
与 3 2 1
不同,请将其子集化以获取您想要的行。
df <- expand.grid(1:6, 1:6, 1:6)
df[df$Var1 <= df$Var2 & df$Var2 <= df$Var3,]
#
# Var1 Var2 Var3
# 1 1 1 1
# 37 1 1 2
# 43 1 2 2
# 44 2 2 2
# 73 1 1 3
# 79 1 2 3
# 80 2 2 3
# 85 1 3 3
# 86 2 3 3
# 87 3 3 3
# 109 1 1 4
# 115 1 2 4
# 116 2 2 4
# 121 1 3 4
# 122 2 3 4
# 123 3 3 4
# 127 1 4 4
# 128 2 4 4
# 129 3 4 4
# 130 4 4 4
# 145 1 1 5
# 151 1 2 5
# 152 2 2 5
# 157 1 3 5
# 158 2 3 5
# 159 3 3 5
# 163 1 4 5
# 164 2 4 5
# 165 3 4 5
# 166 4 4 5
# 169 1 5 5
# 170 2 5 5
# 171 3 5 5
# 172 4 5 5
# 173 5 5 5
# 181 1 1 6
# 187 1 2 6
# 188 2 2 6
# 193 1 3 6
# 194 2 3 6
# 195 3 3 6
# 199 1 4 6
# 200 2 4 6
# 201 3 4 6
# 202 4 4 6
# 205 1 5 6
# 206 2 5 6
# 207 3 5 6
# 208 4 5 6
# 209 5 5 6
# 211 1 6 6
# 212 2 6 6
# 213 3 6 6
# 214 4 6 6
# 215 5 6 6
# 216 6 6 6
下面是一个通用函数,可让您指定对输出的约束。例如,我遇到过很多情况,我需要给定集合的所有 n 元组,以便积小于给定的界限。在我写这个函数之前,我被迫使用 combinations
并搜索那些满足我条件的行。这花了很多时间和很多内存。
Combo <- function(n,r,v=1:n,li=10^8,fun1="prod",fun2="<",repeats.allowed=FALSE) {
## where fun1 is a general function such as "prod", "sum", "sd", etc.
## and fun2 is a comparison operator such as "<", "<=", ">", "==", etc.
myfun <- match.fun(FUN = fun1)
operator1 <- match.fun(FUN = fun2)
operator2 <- match.fun(FUN = fun2)
myv <- sort(v)
if (fun2 %in% c(">",">=")) {
myv <- rev(myv)
TheLim <- min(v)
} else {
TheLim <- max(v)
if (fun2 == "==") {
operator1 <- match.fun(FUN = "<=")
}
}
if (!repeats.allowed) {
m <- matrix(numeric(0),combinat::nCm(n,r),r)
v1 <- myv; n1 <- length(v); t <- TRUE; count <- 0L
while (t) {
t <- operator1(myfun(v1[1:r]),li)
while (t && length(v1)>=r) {
t_1 <- operator2(myfun(v1[1:r]),li)
if (t_1) {count <- count+1L; m[count,] <- v1[1:r]}
v1 <- v1[-r]
t <- operator1(myfun(v1[1:r],na.rm=TRUE),li)
}
if (t) {
s <- 1:length(v1)
mymax <- myv[n1-(r-s)]
t1 <- which(!v1==mymax)
if (length(t1)>0) {
e <- max(t1)
v1[e] <- myv[which(myv==v1[e])+1L]
v1 <- c(v1[1:e],myv[(which(myv==v1[e])+1L):n1])
} else {
return(m[!is.na(m[,1]),])
}
} else {
r1 <- r-1L
while (r1>=1L && !t) {
v1[r1] <- myv[which(myv==v1[r1])+1L]
if (v1[r1]==TheLim) {r1 <- r1-1L; next}
v1 <- c(v1[1:r1],myv[(which(myv==v1[r1])+1L):n1])
t <- operator1(myfun(v1[1:r],na.rm=TRUE),li) && length(v1)>=r
r1 <- r1-1L
}
if (!t) {return(m[!is.na(m[,1]),])}
}
}
} else {
MySet <- 1:n
for (i in 1:(r-1L)) {MySet <- sapply(1:n, function(x) sum(MySet[1:x]))}
m <- matrix(numeric(0),nrow=MySet[n],ncol=r)
v1 <- c(rep(myv[1], r),myv[2:n]); n1 <- length(v); t <- TRUE; count <- 0L
while (t) {
t <- operator1(myfun(v1[1:r]),li)
while (t && length(v1)>=r) {
t_1 <- operator2(myfun(v1[1:r]),li)
if (t_1) {count <- count+1L; m[count,] <- v1[1:r]}
v1 <- v1[-r]
t <- operator1(myfun(v1[1:r],na.rm=TRUE),li)
}
if (t) {
s <- 1:length(v1)
t1 <- which(!v1==TheLim)
if (length(t1)>0) {
e <- max(t1)
v1[e] <- myv[which(myv==v1[e])+1L]
tSize <- r - length(myv[1:e])
if (!v1[e]==TheLim) {
v1 <- c(v1[1:e],rep(v1[e],tSize),myv[(which(myv==v1[e])+1L):n1])
} else {
v1 <- c(v1[1:e],rep(v1[e],tSize))
}
} else {
return(m[!is.na(m[,1]),])
}
} else {
r1 <- r-1L
while (r1>=1L && !t) {
if (v1[r1]==TheLim) {r1 <- r1-1L; next}
v1[r1] <- myv[which(myv==v1[r1])+1L]
tSize <- r - length(myv[1:r1])
v1 <- c(v1[1:r1],rep(v1[r1],tSize),myv[(which(myv==v1[r1])+1L):n1])
t <- operator1(myfun(v1[1:r],na.rm=TRUE),li) && length(v1)>=r
r1 <- r1-1L
}
if (!t) {return(m[!is.na(m[,1]),])}
}
}
}
}
下面是一些例子:
## return all 3-tuple combinations of 1 through 6 such
## that the PRODUCT is less than 10
> Combo(n=6, r=3, v=1:6, li=10, fun1="prod", fun2="<", repeats.allowed=TRUE)
[,1] [,2] [,3]
[1,] 1 1 1
[2,] 1 1 2
. . .
[10,] 1 3 3
[11,] 2 2 2
## return all 3-tuple combinations of 1 through 6 such
## that the SUM is less than 10
> Combo(n=6, r=3, v=1:6, li=10, fun1="sum", fun2="<", repeats.allowed=TRUE)
[,1] [,2] [,3]
[1,] 1 1 1
[2,] 1 1 2
[3,] 1 1 3
. . .
[20,] 2 3 3
[21,] 2 3 4
[22,] 3 3 3
这里有一些涉及素数的很酷的例子:
> library(numbers)
> myps <- Primes(1000)
> system.time(t1 <- Combo(n=length(myps), r=3, v=myps, li=10^5, fun1="prod", fun2="<", repeats.allowed=TRUE))
user system elapsed
0.18 0.00 0.18
> nrow(t1)
[1] 13465
> set.seed(42)
> t1[sample(nrow(t1),5),]
[,1] [,2] [,3]
[1,] 13 31 197
[2,] 17 19 167
[3,] 2 131 227
[4,] 11 11 751
[5,] 5 31 151
> object.size(t1)
323360 bytes
> system.time(t2 <- combinations(n=length(myps), r=3, v=myps, repeats.allowed=TRUE))
user system elapsed
3.63 0.00 3.68
> nrow(t2)
[1] 804440
> system.time(t3 <- t2[which(sapply(1:nrow(t2), function(x) prod(t2[x,]) < 10^5)),])
user system elapsed
1.55 0.00 1.54
> nrow(t3)
[1] 13465
> object.size(t2)
19306760 bytes
如您所见,Combo
函数要快得多并且一步执行,而 combinations/sapply
二重奏很慢(超过 5 秒)并且有两个笨拙的步骤。 Combo
函数还 return 一个几乎小 60 倍的对象。
这是另一个很酷的例子。假设您想找到前 168 个素数(即素数 < 1000)的所有三元组,使得标准偏差小于 50。没问题(与上述设置相同):
> system.time(t1 <- Combo(n=length(myps), r=3, v=myps, li=50, fun1="sd", fun2="<", repeats.allowed=TRUE))
user system elapsed
1.49 0.00 1.48
> system.time(t3 <- t2[which(sapply(1:nrow(t2), function(x) sd(t2[x,]) < 50)),])
user system elapsed
19.89 0.00 19.89
> nrow(t1)
[1] 22906
> nrow(t3)
[1] 22906
> all(t3==t1)
[1] TRUE
需要注意的是,并非所有功能组合都有效。例如,如果你让 fun1="sd"
和 fun2=">"
,上面的代码将 return 0 匹配。干杯!
假设我有 6 个号码:
a <- c(1,2,3,4,5,6)
我想列出这 6 个数字的所有可能的 3 位组合,包括重复。
期望的结果如下所示:
1 1 1
1 2 3
1 2 4
...
我不想包含具有相同 3 个数字但顺序不同的元素:
例如
1 2 3
3 2 1
应排除其中之一
一个简单的方法是使用三个 for 循环。这个结果是你想要的吗?
for (x in 1:6) {
for (y in x:6) {
for (z in y:6) {
print(paste(x,y,z))
}
}
}
gtools
中的 combinations
函数可以做到这一点:
library(gtools)
combinations(n=6, r=3, v=a, repeats.allowed=TRUE)
[,1] [,2] [,3] [1,] 1 1 1 [2,] 1 1 2 [3,] 1 1 3 ... [54,] 5 5 6 [55,] 5 6 6 [56,] 6 6 6
expand.grid
returns 一个 data.frame 的组合,从你提供的每一组中挑选一个。如果 1 2 3
与 3 2 1
不同,请将其子集化以获取您想要的行。
df <- expand.grid(1:6, 1:6, 1:6)
df[df$Var1 <= df$Var2 & df$Var2 <= df$Var3,]
#
# Var1 Var2 Var3
# 1 1 1 1
# 37 1 1 2
# 43 1 2 2
# 44 2 2 2
# 73 1 1 3
# 79 1 2 3
# 80 2 2 3
# 85 1 3 3
# 86 2 3 3
# 87 3 3 3
# 109 1 1 4
# 115 1 2 4
# 116 2 2 4
# 121 1 3 4
# 122 2 3 4
# 123 3 3 4
# 127 1 4 4
# 128 2 4 4
# 129 3 4 4
# 130 4 4 4
# 145 1 1 5
# 151 1 2 5
# 152 2 2 5
# 157 1 3 5
# 158 2 3 5
# 159 3 3 5
# 163 1 4 5
# 164 2 4 5
# 165 3 4 5
# 166 4 4 5
# 169 1 5 5
# 170 2 5 5
# 171 3 5 5
# 172 4 5 5
# 173 5 5 5
# 181 1 1 6
# 187 1 2 6
# 188 2 2 6
# 193 1 3 6
# 194 2 3 6
# 195 3 3 6
# 199 1 4 6
# 200 2 4 6
# 201 3 4 6
# 202 4 4 6
# 205 1 5 6
# 206 2 5 6
# 207 3 5 6
# 208 4 5 6
# 209 5 5 6
# 211 1 6 6
# 212 2 6 6
# 213 3 6 6
# 214 4 6 6
# 215 5 6 6
# 216 6 6 6
下面是一个通用函数,可让您指定对输出的约束。例如,我遇到过很多情况,我需要给定集合的所有 n 元组,以便积小于给定的界限。在我写这个函数之前,我被迫使用 combinations
并搜索那些满足我条件的行。这花了很多时间和很多内存。
Combo <- function(n,r,v=1:n,li=10^8,fun1="prod",fun2="<",repeats.allowed=FALSE) {
## where fun1 is a general function such as "prod", "sum", "sd", etc.
## and fun2 is a comparison operator such as "<", "<=", ">", "==", etc.
myfun <- match.fun(FUN = fun1)
operator1 <- match.fun(FUN = fun2)
operator2 <- match.fun(FUN = fun2)
myv <- sort(v)
if (fun2 %in% c(">",">=")) {
myv <- rev(myv)
TheLim <- min(v)
} else {
TheLim <- max(v)
if (fun2 == "==") {
operator1 <- match.fun(FUN = "<=")
}
}
if (!repeats.allowed) {
m <- matrix(numeric(0),combinat::nCm(n,r),r)
v1 <- myv; n1 <- length(v); t <- TRUE; count <- 0L
while (t) {
t <- operator1(myfun(v1[1:r]),li)
while (t && length(v1)>=r) {
t_1 <- operator2(myfun(v1[1:r]),li)
if (t_1) {count <- count+1L; m[count,] <- v1[1:r]}
v1 <- v1[-r]
t <- operator1(myfun(v1[1:r],na.rm=TRUE),li)
}
if (t) {
s <- 1:length(v1)
mymax <- myv[n1-(r-s)]
t1 <- which(!v1==mymax)
if (length(t1)>0) {
e <- max(t1)
v1[e] <- myv[which(myv==v1[e])+1L]
v1 <- c(v1[1:e],myv[(which(myv==v1[e])+1L):n1])
} else {
return(m[!is.na(m[,1]),])
}
} else {
r1 <- r-1L
while (r1>=1L && !t) {
v1[r1] <- myv[which(myv==v1[r1])+1L]
if (v1[r1]==TheLim) {r1 <- r1-1L; next}
v1 <- c(v1[1:r1],myv[(which(myv==v1[r1])+1L):n1])
t <- operator1(myfun(v1[1:r],na.rm=TRUE),li) && length(v1)>=r
r1 <- r1-1L
}
if (!t) {return(m[!is.na(m[,1]),])}
}
}
} else {
MySet <- 1:n
for (i in 1:(r-1L)) {MySet <- sapply(1:n, function(x) sum(MySet[1:x]))}
m <- matrix(numeric(0),nrow=MySet[n],ncol=r)
v1 <- c(rep(myv[1], r),myv[2:n]); n1 <- length(v); t <- TRUE; count <- 0L
while (t) {
t <- operator1(myfun(v1[1:r]),li)
while (t && length(v1)>=r) {
t_1 <- operator2(myfun(v1[1:r]),li)
if (t_1) {count <- count+1L; m[count,] <- v1[1:r]}
v1 <- v1[-r]
t <- operator1(myfun(v1[1:r],na.rm=TRUE),li)
}
if (t) {
s <- 1:length(v1)
t1 <- which(!v1==TheLim)
if (length(t1)>0) {
e <- max(t1)
v1[e] <- myv[which(myv==v1[e])+1L]
tSize <- r - length(myv[1:e])
if (!v1[e]==TheLim) {
v1 <- c(v1[1:e],rep(v1[e],tSize),myv[(which(myv==v1[e])+1L):n1])
} else {
v1 <- c(v1[1:e],rep(v1[e],tSize))
}
} else {
return(m[!is.na(m[,1]),])
}
} else {
r1 <- r-1L
while (r1>=1L && !t) {
if (v1[r1]==TheLim) {r1 <- r1-1L; next}
v1[r1] <- myv[which(myv==v1[r1])+1L]
tSize <- r - length(myv[1:r1])
v1 <- c(v1[1:r1],rep(v1[r1],tSize),myv[(which(myv==v1[r1])+1L):n1])
t <- operator1(myfun(v1[1:r],na.rm=TRUE),li) && length(v1)>=r
r1 <- r1-1L
}
if (!t) {return(m[!is.na(m[,1]),])}
}
}
}
}
下面是一些例子:
## return all 3-tuple combinations of 1 through 6 such
## that the PRODUCT is less than 10
> Combo(n=6, r=3, v=1:6, li=10, fun1="prod", fun2="<", repeats.allowed=TRUE)
[,1] [,2] [,3]
[1,] 1 1 1
[2,] 1 1 2
. . .
[10,] 1 3 3
[11,] 2 2 2
## return all 3-tuple combinations of 1 through 6 such
## that the SUM is less than 10
> Combo(n=6, r=3, v=1:6, li=10, fun1="sum", fun2="<", repeats.allowed=TRUE)
[,1] [,2] [,3]
[1,] 1 1 1
[2,] 1 1 2
[3,] 1 1 3
. . .
[20,] 2 3 3
[21,] 2 3 4
[22,] 3 3 3
这里有一些涉及素数的很酷的例子:
> library(numbers)
> myps <- Primes(1000)
> system.time(t1 <- Combo(n=length(myps), r=3, v=myps, li=10^5, fun1="prod", fun2="<", repeats.allowed=TRUE))
user system elapsed
0.18 0.00 0.18
> nrow(t1)
[1] 13465
> set.seed(42)
> t1[sample(nrow(t1),5),]
[,1] [,2] [,3]
[1,] 13 31 197
[2,] 17 19 167
[3,] 2 131 227
[4,] 11 11 751
[5,] 5 31 151
> object.size(t1)
323360 bytes
> system.time(t2 <- combinations(n=length(myps), r=3, v=myps, repeats.allowed=TRUE))
user system elapsed
3.63 0.00 3.68
> nrow(t2)
[1] 804440
> system.time(t3 <- t2[which(sapply(1:nrow(t2), function(x) prod(t2[x,]) < 10^5)),])
user system elapsed
1.55 0.00 1.54
> nrow(t3)
[1] 13465
> object.size(t2)
19306760 bytes
如您所见,Combo
函数要快得多并且一步执行,而 combinations/sapply
二重奏很慢(超过 5 秒)并且有两个笨拙的步骤。 Combo
函数还 return 一个几乎小 60 倍的对象。
这是另一个很酷的例子。假设您想找到前 168 个素数(即素数 < 1000)的所有三元组,使得标准偏差小于 50。没问题(与上述设置相同):
> system.time(t1 <- Combo(n=length(myps), r=3, v=myps, li=50, fun1="sd", fun2="<", repeats.allowed=TRUE))
user system elapsed
1.49 0.00 1.48
> system.time(t3 <- t2[which(sapply(1:nrow(t2), function(x) sd(t2[x,]) < 50)),])
user system elapsed
19.89 0.00 19.89
> nrow(t1)
[1] 22906
> nrow(t3)
[1] 22906
> all(t3==t1)
[1] TRUE
需要注意的是,并非所有功能组合都有效。例如,如果你让 fun1="sd"
和 fun2=">"
,上面的代码将 return 0 匹配。干杯!