Skip to content

Instantly share code, notes, and snippets.

@alandipert
Last active June 28, 2018 16:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alandipert/ba3f925a31c67cd08966ad4ea220e541 to your computer and use it in GitHub Desktop.
Save alandipert/ba3f925a31c67cd08966ad4ea220e541 to your computer and use it in GitHub Desktop.
# Like Map but expects f to return a list and concatenates results.
Mapcan <- function(f, xs) Reduce(append, Map(f, xs))
# Returns a list of named lists, each with `name` and `value` values, for the
# given named list.
as_entries <- function(named_list) {
Map(function(name) list(key = name, val = named_list[[name]]), names(named_list))
}
# Returns a list of lists, each starting with the leaf value and followed by the path to that leaf.
paths <- function(parent, x) {
if (typeof(x) == "list") {
# Named list aka JSON object
if (!is.null(names(x))) {
Mapcan(function(entry) {
paths(c(parent, entry$key), entry$val)
}, as_entries(x))
# Unnamed list aka JSON array
} else if (length(x) > 0) {
Mapcan(function(i) {
paths(c(parent, i), x[[i]])
}, 1:length(x))
}
} else {
# Leaf, so return the leaf value followed by its path
list(c(list(x), parent))
}
}
# Returns a data frame where each row is a distinct path into a tree of lists,
# such as that produced by jsonlite::fromJSON. Useful for querying deeply-nested
# structures in a tabular fashion.
tree_df <- function(tree) {
ps <- paths(list(), tree)
# Ensure rows are all the same length, with NA for padding
longest <- max(unlist(Map(length, ps)))
padded <- Map(function(path) {
c(as.list(path), rep(NA, longest-length(path)))
}, ps)
as.data.frame(do.call(rbind, padded))
}
# Terrible data
stuff <- list(
alan = list(
type = "person",
percent_water = 70
),
bob = list(
type = "rock",
percent_rock = 100
)
)
# Find names of any items made out of more than 80% of something
df <- tree_df(stuff)
df <- subset(df, sapply(df$V1, is.numeric))
item_names <- subset(df, df$V1 > 80)[,"V2"]
# item_names = list("bob")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment