为何dplyr的case_when函数兼容grepl却不兼容grep?
为啥
grep在case_when里没效果,grepl却正常? 嘿,这个问题的关键其实是**grepl和grep返回的东西完全不一样**,而dplyr的case_when对条件格式有硬性要求——每个条件都得是和输入向量长度一致的逻辑向量(就是每个元素对应TRUE或者FALSE那种)。
先搞懂俩函数的核心区别
grepl("fizz", v):会返回一个和v长度一模一样的向量,每个位置告诉你这个元素里有没有匹配到目标模式。比如你的v是50个元素,它就给你50个TRUE/FALSE,刚好能让case_when逐个判断每个元素该走哪个分支。grep("fizz", v):它返回的是那些匹配上的元素的位置编号,比如v里第5、10、15...个元素是"fizz",它就返回c(5,10,15,...),这个向量的长度是匹配到的元素个数,不是原向量的50个。case_when根本没法把这个短向量对应到每个元素的判断上,自然就“不生效”了。
拿你的代码举例子验证
能正常运行的写法(用grepl)
library(dplyr) x <- 1:50 v <- case_when( x %% 35 == 0 ~ "fizz buzz", x %% 5 == 0 ~ "fizz", x %% 7 == 0 ~ "buzz", TRUE ~ as.character(x) ) # 输出符合预期的结果 case_when( grepl("fizz", v) ~ "FFF", grepl("buzz", v) ~ "BZZ", TRUE ~ as.character(v) )
为啥直接用grep不行?
如果换成grep,代码是这样的:
# 要么结果完全不符合预期,要么直接报错 case_when( grep("fizz", v) ~ "FFF", grep("buzz", v) ~ "BZZ", TRUE ~ as.character(v) )
这里grep返回的是一堆位置数字,case_when会把这个短向量循环重复去匹配长向量的长度,这完全不是你想要的逐元素判断逻辑,所以看起来就像是没生效。
非要用grep的话怎么改?
可以把grep返回的索引转换成逻辑向量,用seq_along(v)生成原向量的位置序列,再用%in%判断每个位置是不是在匹配索引里:
case_when( seq_along(v) %in% grep("fizz", v) ~ "FFF", seq_along(v) %in% grep("buzz", v) ~ "BZZ", TRUE ~ as.character(v) )
这样就能得到和v长度一致的逻辑向量,case_when就能正常工作了。不过说实话,直接用grepl要简洁得多,没必要多这一步~
内容的提问来源于stack exchange,提问作者Joon
相关产品推荐
相关产品推荐

