如何在R语言向量中查找值的首次出现,不存在时返回向量长度?
在R中查找指定值首次出现位置并按组切片数据框的优化方案
需求说明
核心需求分为两部分:
- 向量处理:查找指定值的首次出现位置;若该值不存在,则返回向量的长度。
- 数据框应用:按组切片数据框,保留从首行到包含指定值首次出现的行;若值不存在则保留所有行。
现有实现及问题
先看原始的错误尝试,这类方法无法满足需求:
x <- 0:1 y <- c(0:2, 2) z <- c(y, 3) # 这类max(which())的方法不适用 max(which(x < 2)) #> [1] 2 ## 期望结果应为3(x中没有2,需返回向量长度) max(which(y < 2)) #> [1] 2 ## !=的方式同样无法得到正确结果 max(which(z != 2)) #> [1] 5
现有可行的实现代码:
library(dplyr) # 向量处理的现有方案 my_vecs <- list(x, y, z) my_len <- lengths(my_vecs) my_ind <- sapply(my_vecs, function(u) which(u == 2)[1]) coalesce(my_ind, my_len) #> [1] 2 3 3 # 数据框处理的现有方案 foo <- data.frame(id = letters[rep(my_len, my_len)], n = c(x,y,z)) foo %>% group_by(id) %>% mutate(cens = which(n == 2)[1], cens = ifelse(is.na(cens), n(), cens)) %>% slice(1:max(cens)) #> # A tibble: 8 × 3 #> # Groups: id [3] #> id n cens #> <chr> <dbl> <int> #> 1 b 0 2 #> 2 b 1 2 #> 3 d 0 3 #> 4 d 1 3 #> 5 d 2 3 #> 6 e 0 3 #> 7 e 1 3 #> 8 e 2 3
更优实现方案
1. 向量处理优化
用match()替代which()[1],match()会直接返回指定值的首次匹配位置,无匹配时返回NA,结合coalesce可以更简洁高效地实现需求:
sapply(my_vecs, function(u) coalesce(match(2, u), length(u))) #> [1] 2 3 3
优势:match()是R内置的向量化函数,比sapply结合which()的循环方式性能更优,尤其适合处理大规模向量。
2. 数据框处理优化
简化dplyr流程
省去ifelse,直接用coalesce处理match的结果,简化逻辑:
foo %>% group_by(id) %>% mutate(cens = coalesce(match(2, n), n())) %>% slice(1:cens)
进一步精简:无需mutate
直接在slice中计算目标位置,减少中间变量,代码更紧凑:
foo %>% group_by(id) %>% slice(1:coalesce(match(2, n), n()))
大数据场景:data.table实现
如果处理大规模数据,data.table的分组操作性能更出色:
library(data.table) setDT(foo) foo[, .SD[1:coalesce(match(2, n), .N)], by = id]
内容的提问来源于stack exchange,提问作者tjebo
相关产品推荐
相关产品推荐

