找出向量中小于阈值的最后一个元素的下标

编程语言 2026-07-08

假设我有一个向量,v

v<-c(1,3,5,8,8,5,6,8,9,10)

其中的数值大致在增大,但并非完全均匀地增大。

我想要返回小于阈值的最后一个值的索引,在这个例子中阈值为 < 8。因此期望的输出应为7(也就是值为6 的那个元素的索引)。

将数据按小于8 进行子集提取并统计得到的向量长度并不能解决问题,因为在我们要找的值之前,可能已经出现了大于等于阈值的值。

我曾考虑用从向量末端向前搜索的for循环并返回第一个小于8 的值的索引,但这似乎是一种过于复杂的解法。

解决方案

获取满足条件的元素的索引,并取最后一个:

# 1
tail(which(v < 8), 1)
## [1] 7

上述方法在没有满足条件的元素时会返回一个长度为0 的结果。若要指定不同的结果,请使用这个(这里我们指定了NA,但它可以替换为任意期望的值,例如0):

# 2
(v < 0) |>
  which() |>
  tail(1) |>
  c(NA) |>
  head(1)
## [1] NA

或这个也可以很容易地做成一个接收逻辑向量和默认值的短函数:

# 3
(v < 0) |>
  which() |>
  (\(x) if (length(x)) tail(x, 1) else NA)()
## [1] NA

这个在没有匹配时返回NA:

# 4
rev(which(v < 0))[1]
## [1] NA

这个在没有匹配时返回0。它的效率比前面的实现低,但如果 v 的规模不大,或许也无所谓:

# 5
Reduce(max, init = 0, which(v < 0))
## [1] 0

性能

library(bench)
library(dplyr)
library(ggplot2)
v = c(1,3,5,8,8,5,6,8,9,10)
L <- list(v10 = v, v100 = sample(v, 100, TRUE), v1000 = sample(v, 1000, TRUE))

results <- press(
  i = 1:3,
  k = c(0, 8),
  { v = L[[i]]
    mark(min_iterations = 100,
      tail1 = c(tail(which(v < k), 1), NA)[[1]],
      tail2 = (v < k) |> which() |> tail(1) |> c(NA) |> head(1),
      tail3 = (v < k) |> which() |> (\(x) if (length(x)) tail(x, 1) else NA_integer_)(),
      rev = rev(which(v < k))[1],
      Reduce = Reduce(max, init = 0, which(v < k)) |> na_if(0L),
      Position = Position(\(x) x < k, v, right=TRUE)
    )
  }
)

autoplot(results)

图片

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章