SelectorChecker.R 9.22 KB
Newer Older
SelectorChecker <- function(selectors, var = NULL, return_indices = TRUE,
                            tolerance = NULL) {
  if (length(selectors) == 0) {
    stop("No selectors provided in 'selectors'.")
  }
  if (return_indices) {
    if (is.list(selectors)) {
      if (length(selectors) != 2) {
        stop("'selectors' provided in a wrong format.")
      }
      crescent_selectors <- TRUE
      if (all(sapply(selectors, 
        function(x) {
          any(c('numeric', "POSIXct", "POSIXlt", "POSIXt", "Date") %in% class(x))
        }))) {
        if (selectors[[2]] < selectors[[1]]) {
          crescent_selectors <- FALSE
        }
      }
      for (i in 1:length(selectors)) {
        if (is.null(var)) {
Nicolau Manubens's avatar
Nicolau Manubens committed
          if (!is.numeric(selectors[[i]])) {
            stop("No selector values provided in 'var'.")
          } else {
            selectors[[i]] <- round(selectors[[i]])
          }
        } else if (is.na(selectors[[i]])) {
          if (i == 1) {
            if (crescent_selectors) {
              selectors[[i]] <- 1
            } else {
              selectors[[i]] <- length(var)
            }
          }
          else {
            if (crescent_selectors) {
              selectors[[i]] <- length(var)
            } else {
              selectors[[i]] <- 1
            }
          }
        } else if (is.character(selectors[[i]])) {
          if (is.character(var)) {
            candidate <- which(var == selectors[[i]])
            if (length(candidate) > 0) {
              selectors[[i]] <- candidate[1]
            } else {
              stop("Selector value not found in 'var'.")
            }
          } else {
            stop("Character selectors provided but possible values in 'var' are not character.")
          }
        } else if (is.numeric(selectors[[i]])) {
          if (is.numeric(var)) {
            tol <- 0
            if (!is.null(tolerance)) {
              if (!any(class(tolerance) %in% "numeric")) {
                stop("Expected a numeric *_tolerance.")
              }
              tol <- tolerance
            }

            val <- selectors[[i]]

              if (crescent_selectors) {
                val <- val - tol
                if (var[1] < var[2]) {
                  selectors[[i]] <- which(var >= val)[1]
                } else if (var[1] > var[2]) {
                  selectors[[i]] <- rev(which(var >= val))[1]
                }

              } else {
                val <- val + tol
                if (var[1] < var[2]) {
                  selectors[[i]] <- rev(which(var <= val))[1]
                } else if (var[1] > var[2]) {
                  selectors[[i]] <- which(var <= val)[1]
                }
            else if (i == 2) {
              if (crescent_selectors) {
                val <- val + tol
                if (var[1] < var[2]) {
                  selectors[[i]] <- rev(which(var <= val))[1]
                } else if (var[1] > var[2]) {
                  selectors[[i]] <- which(var <= val)[1]
                }

              } else {
                val <- val - tol
                if (var[1] < var[2]) {
                  selectors[[i]] <- which(var >= val)[1]
                } else if (var[1] > var[2]) {
                  selectors[[i]] <- rev(which(var >= val))[1]
                }
          } else {
            stop("Numeric selectors provided but possible values in 'var' are not numeric.")
          }
        } else if (any(c("POSIXct", "POSIXlt", "POSIXt", "Date") %in% class(selectors[[i]]))) {
          # TODO: Here, change to as above (numeric part).
          if (any(c("POSIXct", "POSIXlt", "POSIXt", "Date") %in% class(var))) {
            val <- selectors[[i]]
            tol <- 0
            if (!is.null(tolerance)) {
              if (!any(class(tolerance) %in% "difftime")) {
                stop("Expected a difftime *_tolerance.")
              }
              tol <- tolerance
            }
              if (crescent_selectors) {
                val <- val - tol
                selectors[[i]] <- which(var >= val)[1]
              } else {
                val <- val + tol
                selectors[[i]] <- rev(which(var <= val))[1]
            }
            else {
              if (crescent_selectors) {
                val <- val + tol
                selectors[[i]] <- rev(which(var <= val))[1]
              } else {
                val <- val - tol
                selectors[[i]] <- which(var >= val)[1]
              }
            }
          } else {
            stop("Datetime selectors provided but possible values in 'var' are not datetime.")
          }
      # The checker is returning a list of two indices.
      ##selectors[[1]]:selectors[[2]]
      selectors
    } else if (is.numeric(selectors)) {
      if (is.null(var)) {
        ## TODO: Crash if negative indices?
        round(selectors)
      } else {
        if (is.numeric(var)) {
          if (!all(selectors %in% var)) {
            .warning(paste0("Numeric selectors have been ",
                     "provided for a dimension defined along a ",
                     "numeric variable, but no exact match ",
                     "found for all the selectors. Taking the index of the ",
                     "nearest values."))
          }
          if (!is.null(tolerance)) {
            if (!any(class(tolerance) %in% 'numeric')) {
              stop("Expected a numeric *_tolerance.")
            }
          }
          sapply(selectors, function(x) {
                              dif <- abs(var - x)
                              res <- which.min(dif)[1]
                              if (!is.null(tolerance)) {
                                if (dif[res] > tolerance) {
                                  stop("Could not find a value in 'var' close ",
                                       "enough to one of the 'selectors', ",
                                       "according to 'tolerance'.")
                                }
                              }
                              res
                            })
        } else {
          stop("Numeric selectors provided but possible values in 'var' are not numeric.")
        }
      }
    } else if (any(c('POSIXct', 'POSIXlt', 'POSIXt', 'Date') %in% class(selectors))) {
      if (is.null(var)) {
        stop("Numeric selectors have been provided for a dimension ",
             "defined along a date variable, but no possible values ",
             "provided in 'var'.")
      }
      if (!all(selectors %in% var)) {
        .warning(paste0("Date selectors have been ",
                 "provided for a dimension defined along a ",
                 "date variable, but no exact match ",
                 "found for all the selectors. Taking the index of the ",
                 "nearest values."))
      }
      if (!is.null(tolerance)) {
        if (!any(class(tolerance) %in% 'difftime')) {
          stop("Expected a difftime *_tolerance.")
        }
      }
      sapply(selectors, function(x) {
                          dif <- abs(var - x)
                          res <- which.min(dif)[1]
                          if (!is.null(tolerance)) {
                            if (dif[res] > tolerance) {
                              res <- NA
                              #stop("Could not find a value in 'var' close ",
                              #     "enough to one of the 'selectors', ",
                              #     "according to 'tolerance'.")
    } else {
      if (is.null(var)) {
        stop("No selector values provided in 'var'.")
      } else {
        if ((length(selectors) == 1) && 
            (selectors %in% c('all', 'first', 'last'))) {
          if (selectors == 'all') {
            1:length(var)
          } else if (selectors == 'first') {
            1
          } else {
            length(var)
          }
        } else {
          if (!identical(class(var), class(selectors))) {
            stop("Class of provided selectors does not match class of 'var'.")
          }
aho's avatar
aho committed
          candidates <- match(as.vector(selectors), as.vector(var))
          if (length(candidates) == 0 | any(is.na(candidates))) {
            stop("Selectors do not match values in 'var'.")
          } else if (length(candidates) != length(selectors)) {
            stop("Some selectors do not match values in 'var'.")
          }
          candidates
        }
      }
    }
  } else {
    if (!is.null(var)) {
      if (is.list(selectors)) {
aho's avatar
aho committed
        if (length(selectors) != 2) {
          stop("'selectors' provided in a wrong format.")
        } else {
          var[selectors[[1]]:selectors[[2]]]
        }
      } else if (is.numeric(selectors)) {
        if (length(selectors) > 0) {
          var[selectors]
        } else {
          stop("No selectors provided.")
        }
      } else {
        if ((length(selectors) == 1) && 
            (selectors %in% c('all', 'first', 'last'))) {
          if (selectors == 'all') {
            var
          } else if (selectors == 'first') {
            head(var, 1)
          } else {
            tail(var, 1)
          }
        } else {
          selectors
        }
      }
    } else {
      selectors
    }
  }
}