如何继续删除第一个值,直到向量的总和小于20?

Han*_*Dup 11 loops for-loop r vector while-loop

我正在寻找一个函数,它接受一个向量并不断删除第一个值,直到向量的总和小于20.返回剩余的值.

我已经尝试了for-loop和while循环,但无法找到解决方案.

vec <- c(3,5,3,4,3,9,1,8,2,5)

short <- function(vec){

 for (i in 1:length(vec)){
    while (!is.na((sum(vec)) < 20)){
      vec <- vec[i+1:length(vec)]
      #vec.remove(i)
  }
}
Run Code Online (Sandbox Code Playgroud)

预期输出应为: 1,8,2,5 小于20.

Ron*_*hah 12

查看预期输出,看起来您想要删除值,直到剩余值的总和小于20.

我们可以创建一个函数

drop_20 <- function(vec) {
  tail(vec, sum(cumsum(rev(vec)) < 20))
}

drop_20(vec)
#[1] 1 8 2 5
Run Code Online (Sandbox Code Playgroud)

尝试另一个输入

drop_20(1:10)
#[1]  9 10
Run Code Online (Sandbox Code Playgroud)

打破功能,首先是 vec

vec = c(3,5,3,4,3,9,1,8,2,5)
Run Code Online (Sandbox Code Playgroud)

然后我们rev解决它

rev(vec)
#[1] 5 2 8 1 9 3 4 3 5 3
Run Code Online (Sandbox Code Playgroud)

取累积总和(cumsum)

cumsum(vec)
#[1]  3  8 11 15 18 27 28 36 38 43
Run Code Online (Sandbox Code Playgroud)

找出少于20的企业数量

cumsum(rev(vec)) < 20
 #[1]  TRUE  TRUE  TRUE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE

sum(cumsum(rev(vec)) < 20)
#[1] 4
Run Code Online (Sandbox Code Playgroud)

最后用这些最后的进入子集tail.


稍微修改代码,它也应该能够处理NAs

drop_20 <- function(vec) {
   tail(vec, sum(cumsum(replace(rev(vec), is.na(rev(vec)), 0)) < 20))
}

vec = c(3, 2, NA, 4, 5, 1, 2, 3, 4, 9, NA, 1, 2)
drop_20(vec)
#[1]  3  4  9 NA  1  2
Run Code Online (Sandbox Code Playgroud)

逻辑是我们replace NA用零然后接受cumsum


Sot*_*tos 7

你需要每次删除第一个值,所以你的while循环应该是,

while (sum(x, na.rm = TRUE) >= 20) {
    x <- x[-1]
}

#[1] 1 8 2 5
Run Code Online (Sandbox Code Playgroud)

  • @Sotos它不是while循环本身,而是sums之间的相互作用,while循环和删除.我希望"只删除第一个值"为O(N),假设一系列类型会导致整个行为为O(N ^ 3)而不是O(N).现在我并不是说它总是很糟糕(简单的代码通常都很好,即使它的数量级比它的速度慢),但是我能理解为什么有人会这样的解决方案没有注意到这种行为. (2认同)

Wim*_*pel 6

没有循环的基本解决方案
不是我最可读的代码,但速度非常快(参见下面的基准测试)

rev( rev(vec)[cumsum( replace( rev(vec), is.na( rev(vec) ), 0 ) ) < 20] )
#[1] 1 8 2 5
Run Code Online (Sandbox Code Playgroud)

注意:'借用' NA来自@ Ronak的答案

样本数据
vec = c(3, 2, NA, 4, 5, 1, 2, 3, 4, 9, NA, 1, 2)

基准

microbenchmark::microbenchmark(
  Sotos = { 
    while (sum(vec, na.rm = TRUE) >= 20) {
      vec <- vec[-1] 
    } 
  },
  Ronak = tail(vec, sum(cumsum(replace(rev(vec), is.na(rev(vec)), 0)) < 20)),
  Wimpel = rev( rev(vec)[cumsum( replace( rev(vec), is.na( rev(vec) ), 0 ) ) < 20]),
  WimpelMarkus = vec[rev(cumsum(rev(replace(vec, is.na(vec), 0))) < 20)]
  )


# Unit: microseconds
#         expr      min       lq       mean    median        uq      max neval
#        Sotos 2096.795 2127.373 2288.15768 2152.6795 2425.4740 3071.684   100
#        Ronak   30.127   33.440   42.54770   37.2055   49.4080  101.827   100
#       Wimpel   13.557   15.063   17.65734   16.1175   18.5285   38.261   100
# WimpelMarkus    7.532    8.737   12.60520   10.0925   15.9680   45.491   100
Run Code Online (Sandbox Code Playgroud)