R idiom for vector lookup

2019-07-10 08:30发布

问题:

Here is a function which I wrote:

lookup <- function (keys, values, key, default) {
  found <- which(keys == key)
  if (length(found) == 1) return(values[found])
  if (length(found) == 0) return(default)
  stop("lookup(",keys,",",values,",",key,",",default,"): duplicate keys")
}

and it does what I need just fine:

> lookup(c("a"),c(3),"a",0)
[1] 3
> lookup(c("a"),c(3),"b",0)
[1] 0
> lookup(c("a","a"),c(3),"a",0)
Error in lookup(c("a", "a"), c(3), "a", 0) : lookup(aa,3,a,0): duplicate keys

the question is: does it look stylistically right? am I missing something?

(specifically, I expect this function to be written as a single expression).

I do understand that this involves full vector lookup and, as such, is inefficient, and I should be using data.table if I want this to be fast. Fortunately, the performance in this case is not important as my data is very very small.

Thanks!

回答1:

R has dictionaries built into the language via names

dict <- c("Key1"="val1", "Key2"="val2")

dict[["Key1"]]
# [1] "val1"


dict[["Key3"]]
# Error in dict[["Key3"]] : subscript out of bounds

if you need a function that offers up a default value:

getVal <- function(key, dict=defaultDict) { 
  if (! key %in% names(dict) )
    return(defaultValue)

  dict[[key]]
}


回答2:

I’m not sure why you expect this to be shorter – the logic is in fact in a single expression, just the error handling gets unavoidably messy – and incidentally it’s misleading / wrong. I would also make default optional. Then we get:

lookup <- function (keys, values, key, default = NULL) {
    if (length(keys) != length(values))
        stop('lookup(', keys, ', ', values, ', ', key, ', ', default,
             '): lengths of keys and values mismatch')
    indices <- which(keys == key)
    if (length(indices) > 1)
        stop('lookup(', keys, ', ', values, ', ', key, ', ', default,
             '): ambiguous match')

    if (length(indices) == 0) default else values[indices]
}


标签: r vector lookup