Skip to content
Prev 31955 / 63424 Next

Match .3 in a sequence

Here are 2 other implentations of that match.approx function
which use much less memory (and are faster) when the length
of 'x' and 'list' are long (>100, say).  The first uses 
approx(method="const") to figure out which entries in the
list are just below and above each entry in x and the second 
uses sorting tricks to do the same thing.  Then you only have
to figure out if the closest of those 2 entries is close enough.

The original one above fails when tol>min(diff(sort(list))).

match.approx2 <-
function(x,list,tol=.0001) {
    o1 <- rep.int(c(FALSE,TRUE),
c(length(x),length(list)))[order(c(x,list))]
    o2 <- rep.int(c(FALSE,TRUE),
c(length(x),length(list)))[order(c(x,list))]
   
    below <- approx(list, list, xout=x, method="constant", f=0)$y
    above <- approx(list, list, xout=x, method="constant", f=1)$y
    stopifnot(all(below<=x, na.rm=TRUE), all(above>=x, na.rm=TRUE))
    closestInList <- ifelse(x-below < above-x, below, above)
    closestInList[x<min(list)] <- min(list)
    closestInList[x>max(list)] <- max(list)
    closestInList[abs(x-closestInList)>tol] <- NA
    match(closestInList, list)
}
match.approx3 <-
function(x, list, tol=.0001){
    stopifnot(length(list)>0, !any(is.na(x)), !any(is.na(list)))
    oox <- order(order(x)) # essentially rank(x)
    i <- rep(c(FALSE,TRUE), c(length(x),length(list)))[order(c(x,
list))]
    i <- cumsum(i)[!i] + 1L
    i[i > length(list)] <- NA
    i <- order(list)[i]
    leastUpperBound <- i[oox]
    i <- rep(c(TRUE,FALSE), c(length(list),length(x)))[order(c(list,
x))]
    i <- cumsum(i)[!i]
    i[i < 1L] <- NA
    i <- order(list)[i]
    greatestLowerBound <- i[oox]
    closestInList <-
        ifelse(is.na(greatestLowerBound),
            leastUpperBound, # above max(list)
            ifelse(is.na(leastUpperBound),
                greatestLowerBound, # below min(list)
 
ifelse(x-list[greatestLowerBound]<list[leastUpperBound]-x,
                    greatestLowerBound,
                    leastUpperBound)))
    if (tol<Inf)
        closestInList[abs(x - list[closestInList])>tol] <- NA
    closestInList
}