diff --git a/DESCRIPTION b/DESCRIPTION index 241e1df..7db7197 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,48 +1,48 @@ Package: wmf Type: Package Title: R Code for Wikimedia Foundation Internal Usage -Version: 0.5.0 +Version: 0.5.1 Date: 2018-07-05 Authors@R: c( person("Mikhail", "Popov", email = "mikhail@wikimedia.org", role = c("aut", "cre")), person("Oliver", "Keyes", role = "aut", comment = "No longer employed at the Foundation"), person("Chelsy", "Xie", email = "cxie@wikimedia.org", role = "ctb") ) Description: This package contains functions made for Analysts at Wikimedia Foundation, but can be used by people outside of the Foundation. License: MIT + file LICENSE URL: https://phabricator.wikimedia.org/diffusion/1821/ BugReports: https://phabricator.wikimedia.org/maniphest/task/create/? projects=Product-Analytics Depends: R (>= 3.1.0) Imports: devtools, ggthemes (>= 3.4.0), ggplot2, jsonlite, lubridate, progress, purrr, pwr, Rcpp (>= 0.10.3), readr, RMySQL, tibble, urltools Suggests: lintr, testthat, knitr, rmarkdown, dplyr, tidyr LinkingTo: BH, Rcpp, RcppArmadillo (>= 0.3.810) NeedsCompilation: yes SystemRequirements: C++11 LazyData: TRUE Roxygen: list(markdown = TRUE) RoxygenNote: 6.0.1 VignetteBuilder: knitr diff --git a/R/utils.R b/R/utils.R index 2cff615..5128035 100644 --- a/R/utils.R +++ b/R/utils.R @@ -1,56 +1,55 @@ #' @title Turn Null Into Character "NA" #' @description This function turns `NULL` in a list into character "NA", which #' can be very useful when processing JSON data that has `null` values. #' @param x A list #' @return If any element from the input list is NULL, they will be turned into character #' "NA". Otherwise, return the original list. #' @examples \dontrun{ #' result <- mysql_read("SELECT userAgent FROM ...", "log") #' ua <- purrr::map_df( #' result$userAgent, #' ~ null2na(jsonlite::fromJSON(.x, simplifyVector = FALSE)) #' ) #' } #' @export null2na <- function(x) { return(lapply(x, function(y) { if (is.null(y)) { return(as.character(NA)) } else { return(y) } })) } #' @title Parse character vector of JSON #' @description This is a shortcut for using [purrr::map()] with #' [jsonlite::fromJSON()]. Useful when a column in a `data.frame` has JSON. #' **Note**: if the intention is to have the parsed data in a column such as #' when parsing in [dplyr::mutate()], it is *highly* recommended to switch #' to a `tibble` via [tibble::as_tibble()] *first*. #' @param x A character vector of JSON #' @export parse_json <- function(x) { return(purrr::map(x, jsonlite::fromJSON)) } #' @title Invert list #' @description Inverts a (named) list such that the values become the keys and #' the keys become the values. #' @param x A named list #' @return A list with values as keys and keys as values. #' @examples #' invert_list(list(x = c(1, 2), y = c(2, 3))) -#' # returns: list(`1` = "x", `2` = c("x", "y"), `3` = "y") #' @author Mikhail Popov #' @export invert_list <- function(x) { if (is.null(names(x))) stop("expecting input to be a named list") new_fields <- Reduce(union, x) if (length(new_fields) == 0) warning("inverted list will be empty") names(new_fields) <- new_fields return(lapply(new_fields, function(field) { y <- purrr::map_lgl(x, ~ field %in% .x) return(names(y)[y]) })) } diff --git a/man/invert_list.Rd b/man/invert_list.Rd index 7e192bf..30fb719 100644 --- a/man/invert_list.Rd +++ b/man/invert_list.Rd @@ -1,25 +1,24 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/utils.R \name{invert_list} \alias{invert_list} \title{Invert list} \usage{ invert_list(x) } \arguments{ \item{x}{A named list} } \value{ A list with values as keys and keys as values. } \description{ Inverts a (named) list such that the values become the keys and the keys become the values. } \examples{ invert_list(list(x = c(1, 2), y = c(2, 3))) -# returns: list(`1` = "x", `2` = c("x", "y"), `3` = "y") } \author{ Mikhail Popov } diff --git a/tests/testthat/test-utils.R b/tests/testthat/test-utils.R index 019dba6..fd37c77 100644 --- a/tests/testthat/test-utils.R +++ b/tests/testthat/test-utils.R @@ -1,14 +1,22 @@ context("Utilities") test_that("null2na", { # e.g. from jsonlite::fromJSON('{"a":1,"b":null,"c":"d"}'): x <- list(a = 1, b = NULL, c = "d") expect_equal(null2na(x), list(a = 1, b = as.character(NA), c = "d")) }) test_that("parse_json", { x <- c('{"a":[1,2]}', '{"b":3,"c":[4,5]}') y <- parse_json(x) z <- list(list(a = c(1, 2)), list(b = 3, c = c(4, 5))) expect_equal(z, y) }) + +test_that("invert_list", { + x <- list("x" = c(1, 2), y = c(), z = c(2, 3)) + y <- list(`1` = "x", `2` = c("x", "z"), `3` = "z") + expect_equal(invert_list(x), y) + z <- suppressWarnings(invert_list(list(x = c(), y = c(), z = c()))) + expect_equal(z, list()) +})