R范围:1:0-不合逻辑的行为

时间:2018-08-30 20:07:02

标签: r range

我有一个长度为N的数组X,我想计算sum(X[(i+1):N]) - sum(X[1:(i-1)]。如果我的索引i在2 ..(N-1)之内,则可以正常工作。如果等于1,则第二项将返回数组的第一个元素,而不是排除它。如果等于N,则第一项将返回数组的最后一个元素,而不是排除它。 seq_len是我所知道的唯一可以完成此功能的函数,但仅适用于第二项(索引为1:n)。我需要的是一个范围函数,当它的第二个参数低于第一个参数时,它将返回NULL(而不是抛出类似seq的异常)。 sum函数将完成其余的工作。有谁知道一个,还是我必须自己写一个?

1 个答案:

答案 0 :(得分:2)

我建议使用另一种生成索引序列的路径:seq_len,在极端情况下可以直观地做出反应。

最底线:改为使用sum(X[-seq_len(i)]) - sum(X[seq_len(i-1)])

首先,提供一些示例数据:

X <- 1:10
N <- length(X)

您的方法有两个极端:

i <- 1
X[(i+1):N]
# [1]  2  3  4  5  6  7  8  9 10
X[1:(i-1)] # oops
# [1] 1

我相信,应该返回“无”。 (更重要的是,sum(...)应该返回0。对于记录,sum(integer(0))是0。)

i <- 10
X[(i+1):N] # oops
# [1] NA 10
X[1:(i-1)]
# [1] 1 2 3 4 5 6 7 8 9

还有另一个错误,您期望第一个子集“什么都没有”。

相反,我建议您使用seq_len

i <- 1
X[-seq_len(i)]
# [1]  2  3  4  5  6  7  8  9 10
X[seq_len(i-1)]
# integer(0)

i <- 10
X[-seq_len(i)]
# integer(0)
X[seq_len(i-1)]
# [1] 1 2 3 4 5 6 7 8 9

两者看起来都不错,中间的东西很有意义。

i <- 5
X[-seq_len(i)]
# [1]  6  7  8  9 10
X[seq_len(i-1)]
# [1] 1 2 3 4

在这个人为的示例中,我们要寻找的是i的任何值:

1: sum(2:10) -        0 = 54 -  0 =  54
2: sum(3:10) - sum(1:1) = 52 -  1 =  51
3: sum(4:10) - sum(1:2) = 49 -  3 =  46
...
10:        0 - sum(1:9) =  0 - 45 = -45

现在我们得到了:

func <- function(i, x) sum(x[-seq_len(i)]) - sum(x[seq_len(i-1)])
sapply(c(1,2,3,10), func, X)
# [1]  54  51  46 -45

修改

李哲源's answer使我认为您不需要一直重新sum之前和之后的数字。只需执行一次并重新使用它。如果您的向量很大,此方法可能会更快一点。

Xb <- c(0, cumsum(X)[-N])
Xb
#  [1]  0  1  3  6 10 15 21 28 36 45
Xa <- c(rev(cumsum(rev(X)))[-1], 0)
Xa
#  [1] 54 52 49 45 40 34 27 19 10  0
sapply(c(1,2,3,10), function(i) Xa[i] - Xb[i])
# [1]  54  51  46 -45

因此,这表明您在i的任何值处的总和为

Xs <- Xa - Xb
Xs
#  [1]  54  51  46  39  30  19   6  -9 -26 -45

,您可以在其中找到Xs[i]的特定值。无需重复求和。