> a <- factor(1:3)
> b <- c(0,1,2)
> ifelse(b == 0, 5, a[b])
[1] 5 2 1
我希望看到的结果是
5,1,2
原因是a[b]
实际上返回1,2
,其长度与a
不同,因此由于循环而导致ifelse
的结果被破坏。我可以使用
if...else
编写ifelse
,但效率非常低。 如何处理它是常见的方式?> a <- factor(1:3)
> b <- c(0,1,2)
> ifelse(b == 0, 5, a[b])
[1] 5 2 1
5,1,2
原因是a[b]
实际上返回1,2
,其长度与a
不同,因此由于循环而导致ifelse
的结果被破坏。if...else
编写ifelse
,但效率非常低。 如何处理它是常见的方式?a <- factor(1:3)
b <- c(0,1,2)
a = as.numeric(a)
zero_logical = b != 0 # Precompute because if a contains a zero, this will also be replaced by 5
b[zero_logical] <- a[b[zero_logical]]
b[!zero_logical] <- 5
b
[1] 5 1 2
b != 0
,另一个用于 b == 0
,因此与显式循环相比,这应该非常快。我还没有和Paul的答案进行效率比较,但是考虑到这个(可能)特殊情况:
a <- factor(1:3)
b <- c(0,1,2)
a2 <- as.factor(c("5", a))
a2[b + 1]
# [1] 5 1 2
# Levels: 1 2 3 5
如果你要查找的不是b == 0
,那么这种方法很可能行不通。
b[b == 0] <- NA
ifelse(is.na(b), 5, a[b])
之前的两个答案都使用了a[_conditions_]
而不是_conditions_(a[])
,这对你的情况似乎更好;这个答案也有同样的概念 :)
除了其他提到的方法,一种方法是使用类似于a[ifelse(, , b)]
而不是ifelse(, , a[b])
。我能想到的唯一解决方案是在a
的末尾添加一个5
,这样就可以使用a[ifelse(b == 0, which(a == 5), b)]
;当然,在上述调用之前,a
必须被重新分配。
为了避免在你工作的环境中更改a
并避免分配额外的变量(即a
的备份),你可以将所有内容包装在local
中;否则,local
只是看起来很酷的答案,可以避免:
a <- factor(1:3)
b <- c(0,1,2)
res <- local({ # just to keep all environments clean and to not re-assign `a`
a = as.numeric(as.character(a))
a[length(a) + 1] <- 5
a[ifelse(b == 0, which(a == 5), b)]
})
res
#[1] 5 1 2
a
#[1] 1 2 3 #not changed `a`
#Levels: 1 2 3
我想不出更优雅的方式来利用a[ifelse(, , )]
。此外,我不确定是否有任何限制。
希望我没有错过什么重要的东西。
b
中测试负数也会带来问题。但是这个答案也会失败。? - BenBarnes[
如何处理负索引,这很可能发生 :-) - Carl Witthoft