是否有一种简短的方法来检查R中每个变量的不等价性?

时间:2019-06-14 08:29:53

标签: r equality

在尝试解决R中的以下逻辑问题时,我遇到了这种情况:

五名运动员(球衣号码分别为1,2,3,4,5)参加比赛,他们得到的分数是球衣号码乘以他们完成比赛的等级的乘积;也就是说,如果2号球衣的运动员获得第五名,他将获得2 * 5 = 10分。
球衣号码为1的运动员没有获得第四名和第五名的比赛。
比赛结束后这5名运动员的总得分为41。
找到每位运动员完成比赛的排名。

我用下面的代码结束了这个问题,并注意到如果一个变量面临5个以上的变量,检查所有变量彼此之间的不相等可能非常麻烦。例如,在10个变量中,它需要C(10,2)= 45个比较。

for (o in as.integer(1:5)) {
  for (t in as.integer(1:5)) {
    for (th in as.integer(1:5)) {
      for (f in as.integer(1:5)) {
         for (fi in as.integer(1:5)) {
if (o+2*t+3*th+4*f+5*fi == 41 && 
(o != 4 && o != 5) && 
# To check the following way in more complex cases is non-useful
((o!=t) && (o!=th) && (o!=f) && (o!=fi) && (t!=th) && (t!=f) && (t!=fi) && (th!=f) && (th!=fi) && (f!=fi))) {print(c(o,t,th,f,fi))}  
    }}}}}
#     o t th f fi
# [1] 2 5 4 3 1

是否有一种简短的方法来检查R中每个变量之间的不对等性?

来源(原始问题): Mehmet Emrehan HALICI, "Brain Sport 1", 2019 (in Turkish)

4 个答案:

答案 0 :(得分:3)

这可能不是内存效率最高的方法,因为我正在寻找所有可能的组合,但这是我最初对如何处理此问题的想法

#Get all possible combinations of ranks that can be taken
#Player 1 can take any place from 1:3, rest all can take any place from 1:5
df1 <- expand.grid(1:3, 1:5, 1:5, 1:5, 1:5)

#Find combinations where after multiplying by the scores sum of it is 41

df2 <- df1[colSums(t(df1) * 1:5) == 41, ]
#Or
#df2 <- df1[rowSums(t(t(df1) * 1:5)) == 41, ]

#Keep only the rows which have only unique combination of ranks
df2[!apply(df2, 1, anyDuplicated), ]

#    Var1 Var2 Var3 Var4 Var5
#209    2    5    4    3    1

答案 1 :(得分:2)

有一个可以使用的软件包permute

library("permute")
d <- rbind(1:5, allPerms(5))
df <- as.data.frame(d)
names(df) <- c("o", "t", "th", "f", "fi")
subset(df, (o+2*t+3*th+4*f+5*fi == 41) &  (o != 4 & o != 5))

#> subset(df, (o+2*t+3*th+4*f+5*fi == 41) &  (o != 4 & o != 5))
#   o t th f fi
#48 2 5  4 3  1

这是一个变体(可用于n的其他值):

n <- 5
d <- rbind(1:n, allPerms(n))
df <- as.data.frame(d)
names(df) <- paste0("r", 1:n)
subset(df, (d %*% (1:n) == 41) &  (r1 != 4 & r1 != 5))

n <- 5
df <- as.data.frame(rbind(1:n, allPerms(n)))
df <- subset(df, V1 < 4)
subset(df, as.matrix(df) %*% (1:n) == 41)

答案 2 :(得分:1)

我的解决方案是创建自己的置换函数,因此实际上使用jogo建议的permute包可能更简单(并且更有效/更安全)。

该排列利用了我在评论中提到的阶乘数原理:

perm <- function(n, perm){
    pos=seq(n)
    res=integer(n)
    x=rev(seq(n))-1
    for(i in seq(n)){
        y  = 1 + perm%/%factorial(x[i])
        res[i] = pos[y]
        pos=pos[-y]
        perm = perm - factorial(x[i])*(y-1)
    }
    return(res)
}
ord = list()
for(i in seq(factorial(5))-1)
{
    p = perm(5,i)
    if(sum(p*1:5)==41 & p[1] < 4) ord =  append(ord,list(p))
}

ord
## [[1]]
## [1] 2 5 4 3 1

此解决方案使用嵌套的for循环,因此它实际上并不十分适合R,但从算法的角度来看可能很有趣。

答案 3 :(得分:0)

亚伦·海曼(Aaron Hayman)的解决方案:

for (o in as.integer(1:5)) {
  for (t in as.integer(1:5)) {
    for (th in as.integer(1:5)) {
      for (f in as.integer(1:5)) {
         for (fi in as.integer(1:5)) {
if (o+2*t+3*th+4*f+5*fi == 41 && 
(o != 4 && o != 5) && 
( all( (1:5) %in% c(o,t,th,f,fi)) )) { # Trick
print(c(o,t,th,f,fi))}  
    }}}}}
# [1] 2 5 4 3 1

此解决方案效果很好,因为变量的可能值(即1,2,3,4,5)易于处理,并且可以通过all( (1:5) %in% c(o,t,th,f,fi))轻松进行检查。