R/dict.R

Defines functions dict print.dict as.dict str.dict as.dict.list keys keys.dict values values.dict `[.dict` `[[.dict` `[<-.dict` copy copy.dict

Documented in as.dict dict

##' Python-style Dictionaries in R
##'
##' Dictionaries, i.e., hashed key-value pairs, are implemented in \R using
##' environments as a backend.
##'
##' Dictionaries are just hashed \R environments with \code{emptyenv()} as a
##' parent.
##'
##' @section Warning:
##'
##' Dictionaries have \bold{reference semantics}, so modifying a dictionary
##' within a function will modify the dictionary passed in, not a copy! Use the
##' \code{copy} function to duplicate a \code{dict}.
##'
##'
##' @param ... Named arguments used in constructing the dictionary.
##' @param `_size` The number of 'buckets' used. This is the maximum of
##'   \code{29L} and the number of named arguments passed to \code{...}.
##' @export
##' @examples
##' ## Reference semantics -- be careful!
##' x <- dict()
##' y <- x
##' x[["a"]] <- 100
##' print(y[["a"]])
##'
##' ## Use copy to be explicit
##' y <- copy(x)
##' x[["b"]] <- 200
##' try(y[["b"]], silent = TRUE)
##'
##' ## Named lookup can be much faster in a dictionary
##' x <- as.list(1:1E5)
##' names(x) <- paste0("Element_", 1:1E5)
##' dict <- as.dict(x)
##' if (require(microbenchmark)) {
##'   microbenchmark(
##'     x[["Element_1"]],
##'     dict[["Element_1"]],
##'     x[["Element_1000"]],
##'     dict[["Element_1000"]],
##'     x[["Element_100000"]],
##'     dict[["Element_100000"]]
##'   )
##' }
dict <- function(..., `_size` = 29L) {
  dots <- list(...)
  dict <- new.env(parent = emptyenv(), size = max(`_size`, length(dots)))
  names <- names(dots)
  for (i in seq_along(names)) {
    dict[[ names[i] ]] <- dots[[i]]
  }
  class(dict) <- "dict"
  dict
}

##' @export
print.dict <- function(x, ...) {
  cat("Dictionary of ", length(x), " key-value pairs\n", sep = "")
}

##' Coerce an Object to a Dictionary
##' @export
as.dict <- function(x, ...) {
  UseMethod("as.dict")
}

##' @export
str.dict <- function(object, ...) {
  print(object, ...)
  keys <- keys(object)
  invisible(enumerate(keys, function(x, i) {
    cat(" $ ", x, ":", sep="")
    str(get(keys[[i]], envir = object))
  }))
}

##' @export
as.dict.list <- function(x, ...) {
  env <- list2env(x, parent = emptyenv(), hash = TRUE, size = max(29L, length(x)))
  class(env) <- "dict"
  env
}

##' @export
keys <- function(x) {
  UseMethod("keys")
}

##' @export
keys.dict <- function(x) {
  objects(x)
}

##' @export
values <- function(x) {
  UseMethod("values")
}

##' @export
values.dict <- function(x) {
  lapply(keys(x), function(elem) get(elem, envir = x))
}

##' @export
`[.dict` <- function(x, i, j, ..., drop = FALSE) {
  mget(i, envir = x, inherits = FALSE)
}

##' @export
`[[.dict` <- function(x, i, j, ..., drop = FALSE) {
  get(i, envir = x, inherits = FALSE)
}

##' @export
`[<-.dict` <- function(x, i, j, value) {
  invisible(lapply(i, function(key) {
    x[[key]] <- value
  }))
  x
}

##' @export
copy <- function(x) UseMethod("copy")

##' @export
copy.dict <- function(x) {
  output <- list2env(
    x = as.list.environment(x, all.names = TRUE),
    parent = emptyenv(),
    hash = TRUE
  )
  class(output) <- "dict"
  output

}
kevinushey/Kmisc documentation built on May 20, 2019, 9:08 a.m.