【问题标题】:Nested for loops to a more concise structure嵌套 for 循环到更简洁的结构
【发布时间】:2021-06-11 09:45:20
【问题描述】:

我的一个朋友最近问我是否可以在 R 中创建一个由 step 分隔的 N 数字列表,总和为 1。例如,向量 seq(0.1,1,0.1) 中 3 个数字的所有可能组合这个总和 1. 顺序并不重要。

我一直在使用expand.grid,但随着数量的增加,内存需求会激增。由于顺序并不重要,我们认为只考虑一些组合来减少矩阵。如果我们让 111 代表值c(0.1,0.1,0.1),而 123 代表 c(0.1,0.2,0.3),我们只考虑 111、112、113 ... 119、122、123、... 129、133 ... 等。

请注意,我们排除了 121、131 和 132,因为它们等同于 112、113 和 123。这大大减少了要测试的组合数量。为此,我们使用了嵌套的 for 循环,如下所示:

step=.1
lst=list()
for(i in seq(step,1,step)){
  for(j in seq(i,1,step)){
    for(k in seq(j,1,step)){
          print(c(i,j,k));if(sum(c(i,j,k))==1){lst=append(lst,list(c(i,j,k)))}
    }
  }
}
do.call("rbind",lst)

这可行,但我想让它更灵活。现在,要比较 4 个数字而不是 3 个,我需要编写一个新的 for 循环。我在想像all_comb(vector, N) 这样的函数,它相当于上面的嵌套循环,但我找不到它,也不知道如何优雅地实现它。

谢谢!

【问题讨论】:

标签: r


【解决方案1】:

如果你有长向量和高 Ns,这样的函数可能会变得混乱,但它绝对可行。我写了一个快速的,也许可以重构它,但它有效。

它创建一个可以添加的向量索引的唯一向量列表。然后,它使用这个列表来计算总和并将它们作为向量返回,并将计算添加为名称。

all_comb = function(vector,N){
  com = as.list(1:length(vector))
  names(com) = as.character(1:length(vector))
  for(i in 2:N){
    nl = list()
    for(e in com){
      for(vi in 1:length(vector)){
        combo = c(e,vi)
        combo = combo[order(combo)]
        nl[[paste(combo,collapse="+")]]=combo
      }
    }
    com = nl
  }
  
  for(i in 1:length(com)){
    com[[i]] = sum(vector[com[[i]]])
  }
  
  return(unlist(com))
  
}

为了用你的例子测试它,我得到:

> result = all_comb(seq(0.1,1,.1),3)
> print(head(result,n=15))
 1+1+1  1+1+2  1+1+3  1+1+4  1+1+5  1+1+6  1+1+7  1+1+8  1+1+9 1+1+10  1+2+2  1+2+3  1+2+4  1+2+5  1+2+6 
   0.3    0.4    0.5    0.6    0.7    0.8    0.9    1.0    1.1    1.2    0.5    0.6    0.7    0.8    0.9 

> print(names(result)[result==1])
[1] "1+1+8" "1+2+7" "1+3+6" "1+4+5" "2+2+6" "2+3+5" "2+4+4" "3+3+4"

这意味着第一个、第一个和第八个元素等于1,或者第一个、第二个和第七个等于1,依此类推。

您可以在名称上使用strsplit() 来取回原始索引。

【讨论】:

    猜你喜欢
    • 2011-04-23
    • 1970-01-01
    • 1970-01-01
    • 2021-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-26
    • 2012-06-23
    相关资源
    最近更新 更多