R/is_empty.R

Defines functions remove_empty_rows remove_empty_cols empty_rows empty_cols is_empty

Documented in empty_cols empty_rows is_empty remove_empty_cols remove_empty_rows

#' @title Check whether string, list or vector is empty
#' @name is_empty
#' @description This function checks whether a string or character vector (of
#'                length 1), a list or any vector (numeric, atomic) is empty or not.
#'
#'
#' @param x String, character vector of length 1, list or vector.
#' @param first.only Logical, if \code{FALSE} and \code{x} is a character
#'        vector, each element of \code{x} will be checked if empty. If
#'        \code{TRUE}, only the first element of \code{x} will be checked.
#' @return Logical, \code{TRUE} if \code{x} is a character vector or string and
#'           is empty, \code{TRUE} if \code{x} is a vector or list and of length 0,
#'           \code{FALSE} otherwise.
#'
#' @note \code{NULL}- or \code{NA}-values are also considered as "empty" (see
#'         'Examples') and will return \code{TRUE}.
#'
#' @examples
#' x <- "test"
#' is_empty(x)
#'
#' x <- ""
#' is_empty(x)
#'
#' x <- NA
#' is_empty(x)
#'
#' x <- NULL
#' is_empty(x)
#'
#' # string is not empty
#' is_empty(" ")
#'
#' # however, this trimmed string is
#' is_empty(trim(" "))
#'
#' # numeric vector
#' x <- 1
#' is_empty(x)
#' x <- x[-1]
#' is_empty(x)
#'
#' # check multiple elements of character vectors
#' is_empty(c("", "a"))
#' is_empty(c("", "a"), first.only = FALSE)
#'
#' @export
is_empty <- function(x, first.only = TRUE) {
  # do we have a valid vector?
  if (!is.null(x)) {
    # if it's a character, check if we have only one element in that vector
    if (is.character(x)) {
      # characters may also be of length 0
      if (length(x) == 0) return(TRUE)
      # else, check all elements of x
      zero_len <- sapply(x, function(y) {
        # zero chars, so empty?
        l <- nchar(y) == 0
        # if 'x' was empty, we have no chars, so zero_len will be integer(0).
        # check this here, because zero_len needs to be logical
        if (length(l) == 0) l <- TRUE
        l
      })
      # return result for multiple elements of character vector
      if (first.only) {
        return(unname(zero_len)[1])
      } else {
        return(unname(zero_len))
      }
      # we have a non-character vector here. check for length
    } else {
      zero_len <- length(x) == 0
    }
  }
  return(is.null(x) || zero_len || all(is.na(x)))
}


#' @title Return or remove variables or observations that are completely missing
#' @name empty_cols
#'
#' @description These functions check which rows or columns of a data frame completely
#'                contain missing values, i.e. which observations or variables
#'                completely have missing values, and either 1) returns their
#'                indices; or 2) removes them from the data frame.
#'
#'
#' @param x A data frame.
#'
#' @return For \code{empty_cols} and \code{empty_rows}, a numeric (named) vector
#'           with row or column indices of those variables that completely have
#'           missing values.
#'           \cr \cr
#'           For \code{remove_empty_cols} and \code{remove_empty_rows}, a
#'           data frame with "empty" columns or rows removed.
#'
#' @examples
#' tmp <- data.frame(a = c(1, 2, 3, NA, 5),
#'                   b = c(1, NA, 3, NA , 5),
#'                   c = c(NA, NA, NA, NA, NA),
#'                   d = c(1, NA, 3, NA, 5))
#'
#' tmp
#'
#' empty_cols(tmp)
#' empty_rows(tmp)
#'
#' remove_empty_cols(tmp)
#' remove_empty_rows(tmp)
#'
#' @export
empty_cols <- function(x) {
  if ((!is.matrix(x) && !is.data.frame(x)) || ncol(x) < 2)
    vector("numeric")
  else
    which(colSums(is.na(x)) == nrow(x))
}


#' @rdname empty_cols
#' @export
empty_rows <- function(x) {
  if ((!is.matrix(x) && !is.data.frame(x)) || nrow(x) < 2)
    vector("numeric")
  else
    which(rowSums(is.na(x)) == ncol(x))
}


#' @rdname empty_cols
#' @importFrom dplyr select
#' @export
remove_empty_cols <- function(x) {
  # check if we have any empty columns at all
  ec <- empty_cols(x)
  # if yes, removing works, else an empty df would be returned
  if (!sjmisc::is_empty(ec))
    dplyr::select(x, !! -ec)
  else
    x
}


#' @rdname empty_cols
#' @importFrom dplyr slice
#' @export
remove_empty_rows <- function(x) {
  # check if we have any empty rows at all
  er <- empty_rows(x)
  # if yes, removing works, else an empty df would be returned
  if (!sjmisc::is_empty(er))
    dplyr::slice(x, !! -er)
  else
    x
}
strengejacke/sjmisc documentation built on June 21, 2018, 4:55 a.m.