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!
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]]
}
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]
}