7

I have a vector of numbers

f <- c(1, 3, 5, 8, 10, 12, 19, 27)

I want to compare the values in the vector to another number, and find the closest smaller value.

For example, if the input number is 18, then the closest, smaller value in the vector is 12 (position 6 in the vector). If the input is 19, then the result should be the value 19, i.e. the index 7.

Henrik
  • 65,555
  • 14
  • 143
  • 159
heinheo
  • 557
  • 1
  • 4
  • 15

7 Answers7

15

I think this answer is pretty straightforward:

f <- c(1,3,6,8,10,12,19,27)
x <- 18

# find the value that is closest to x
maxless <- max(f[f <= x])
# find out which value that is
which(f == maxless)
John
  • 23,360
  • 7
  • 57
  • 83
8

If your vector f is always sorted, then you can do sum(f <= x)

f <- c(1,3,6,8,10,12,19,27)

x <- 18
sum(f <= x)
# [1] 6

x <- 19
sum(f <= x)
# [1] 7
Gregor Thomas
  • 136,190
  • 20
  • 167
  • 294
4

Try this (not a perfect solution)

x<-c(1,3,6,8,10,12,19,27)
showIndex<-function(x,input){
 abs.diff<-abs(x-input)
 index.value<-unique(ifelse(abs.diff==0,which.min(abs.diff),which.min(abs.diff)-1))
return(index.value)
 }
 showIndex(x,12)
    [1] 6
showIndex(x,19)
[1] 7
user227710
  • 3,164
  • 18
  • 35
  • the problem is that if the inout is 19...then the output would need to be 7 (the index)... – heinheo May 18 '15 at 22:59
  • `which.min(abs(x-18))` gives you the index. I am not sure what you are asking. – user227710 May 18 '15 at 23:01
  • x[which.min(abs(x-19))-1] [1] 18....that is the problem because if the inpout is 19 then it mataches directly the value and there should be no subtraction of 1 – heinheo May 18 '15 at 23:03
2

You could try:

x <- 18
f <- c(1,3,6,8,10,12,19,27)

ifelse(x %in% f, which(f %in% x), which.min(abs(f - x)) - 1)

That way if x is not in f, it will return the nearest previous index. If x is in f, it will return x index.

Steven Beaupré
  • 21,343
  • 7
  • 57
  • 77
  • Beaupre how would I make sure that if I search ftr the nearest value of 19, the thing returns 7 (the index of 19) not 6 (the index of 12)...because of the input is exactly a position in the vector it would need to show that... – heinheo May 18 '15 at 23:05
2

Another one:

which.min(abs(18 - replace(f, f>18, Inf)))
#[1] 6

f[which.min(abs(18 - replace(f, f>18, Inf)))]
#[1] 12

Or as a function:

minsmaller <- function(x,value) which.min(abs(value - replace(x, x>value, Inf)))
minsmaller(f, 18)
#[1] 6
minsmaller(f, 19)
#[1] 7
thelatemail
  • 91,185
  • 12
  • 128
  • 188
0

In a functional programming style:

f <- c(1, 3, 6, 8, 10, 12, 19, 27)
x <- 18
Position(function(fi) fi <= x, f, right = TRUE)
Richie Cotton
  • 118,240
  • 47
  • 247
  • 360
0

There is findInterval:

findInterval(18:19, f)
#[1] 6 7

And building a more concrete function:

ff = function(x, table)
{
    ot = order(table)
    ans = findInterval(x, table[ot]) 
    ot[ifelse(ans == 0, NA, ans)]
}

set.seed(007); sf = sample(f)
sf
#[1] 27  6  1 12 10 19  8  3
ff(c(0, 1, 18, 19, 28), sf)
#[1] NA  3  4  6  1
alexis_laz
  • 12,884
  • 4
  • 27
  • 37