3

I have a vector x:

x <- c(-1,-0.5,-0.1,-0.001,0.5,0.6,0.9)

I want the index of the closest negative value to zero and the closest positive value to zero. In this case, 4 and 5. x is not necessarily sorted.

I can do this by setting numbers to NA:

# negative numbers only
tmp <- x
tmp[x > 0] <- NA
which.max(tmp)
# positive numbers only
tmp <- x
tmp[x < 0] <- NA
which.min(tmp)

But that seems clunky. Any tips?

user111024
  • 723
  • 3
  • 15

3 Answers3

4

good scenario

If you are in the classic case, where

  1. your vector is sorted in increasing order,
  2. it does not include 0,
  3. it has no tied values,

you can simply do the following:

findInterval(0, x, TRUE) + 0:1

If condition 1 does not hold, but condition 2 and 3 still hold, you can do

sig <- order(x)
sig[findInterval(0, x[sig], TRUE) + 0:1]

akrun's answer is fundamentally the same.

bad scenario

Things become tricky once your vector x contains 0 or tied / repeated values, because:

In this situation, you have to adapt Ronak Shah's answer which allows you to exclude 0. But be aware that which may give you multiple indexes if there are repeated values.

Zheyuan Li
  • 71,365
  • 17
  • 180
  • 248
4

Another way could be:

#closest positive value to zero.
which(x == min(x[x > 0]))
#[1] 5

#closest negative value to zero
which(x == max(x[x < 0]))
#[1] 4
Ronak Shah
  • 377,200
  • 20
  • 156
  • 213
3

We could try

rle(sign(x))$lengths[1] + 0:1
#[1] 4 5

if it is unsorted, then

x1 <- sort(x)
match(x1[rle(sign(x1))$lengths[1] + 0:1], x)
akrun
  • 874,273
  • 37
  • 540
  • 662