| Title: | Common Base-R Problems Relating to Lists |
|---|---|
| Description: | Utility functions that help with common base-R problems relating to lists. Lists in base-R are very flexible. This package provides functions to quickly and easily characterize types of lists. That is, to identify if all elements in a list are null, data.frames, lists, or fully named lists. Other functionality is provided for the handling of lists, such as the easy splitting of lists into equally sized groups, and the unnesting of data.frames within fully named lists. |
| Authors: | Richard Aubrey White [aut, cre] (ORCID: <https://orcid.org/0000-0002-6747-1726>), Folkehelseinstituttet [cph] |
| Maintainer: | Richard Aubrey White <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 2026.8.22 |
| Built: | 2026-09-26 06:27:20 UTC |
| Source: | https://github.com/niphr/csutil |
Extracts the unique values of x, applies fn to those unique
values, and maps the results back to the original vector. This avoids
redundant computation when x contains many repeated values.
apply_fn_via_hash_table(x, fn, ...)apply_fn_via_hash_table(x, fn, ...)
x |
A vector whose values need a function applied. |
fn |
A vectorised function, called once on the vector of unique values
of |
... |
Additional arguments passed to |
The function calls fn exactly once, on the vector of unique values of
x. It does not call fn once per element. It does not call
fn once per unique value either. fn MUST therefore be
vectorised. It receives the whole vector of unique values in a single call.
This can dramatically speed up computation when there is a lot of data and
a limited number of unique values. The work fn does scales with the
number of unique values, not with the length of x.
A vector of the same length as x, holding the value of
fn for each element (computed via unique-value lookup). The result
takes its class from the value fn returns.
vignette("csutil", package = "csutil"), which times this
function against a direct call to format().
x <- c("a", "b", "a", "c", "b", "a") apply_fn_via_hash_table(x, toupper) # passing extra arguments to fn nums <- c(1.1, 2.2, 1.1, 3.3) apply_fn_via_hash_table(nums, round, digits = 0)x <- c("a", "b", "a", "c", "b", "a") apply_fn_via_hash_table(x, toupper) # passing extra arguments to fn nums <- c(1.1, 2.2, 1.1, 3.3) apply_fn_via_hash_table(nums, round, digits = 0)
Splits x into a list of consecutive groups. You MUST specify exactly
one of size_of_each_group or number_of_groups. Neither
argument, or both arguments, is an error.
easy_split(x, size_of_each_group = NULL, number_of_groups = NULL)easy_split(x, size_of_each_group = NULL, number_of_groups = NULL)
x |
The vector to split. |
size_of_each_group |
The number of elements in each group. The last group may hold fewer. |
number_of_groups |
The number of groups you request. The function can return fewer groups than you request. See Details. |
Every group has the same length except the last, which may be shorter. The
function preserves the original order of x. It names the list
elements "1", "2" and so on.
number_of_groups is a request, not a guarantee. The function computes
the group size as ceiling(length(x) / number_of_groups). The number
of groups it returns is then
ceiling(length(x) / ceiling(length(x) / number_of_groups)). That
count can be smaller than number_of_groups. For example,
easy_split(1:4, number_of_groups = 3) returns two groups of two.
A list of vectors, holding the elements of x in their original
order. Every element has the same length except the last, which may be
shorter.
vignette("csutil", package = "csutil"), which splits
letters[1:20] both ways.
easy_split(letters[1:20], size_of_each_group = 3) easy_split(letters[1:20], number_of_groups = 3) # number_of_groups is a request: this asks for 3 groups and returns 2 easy_split(1:4, number_of_groups = 3)easy_split(letters[1:20], size_of_each_group = 3) easy_split(letters[1:20], number_of_groups = 3) # number_of_groups is a request: this asks for 3 groups and returns 2 easy_split(1:4, number_of_groups = 3)
Checks two things: that 'x' is a list, and that all elements in 'x' are 'NULL' or data.frames.
is_all_list_elements_null_or_df(x)is_all_list_elements_null_or_df(x)
x |
An object |
TRUE or FALSE.
vignette("csutil", package = "csutil"), which runs all four
predicates on small example lists.
Other list predicates:
is_all_list_elements_null_or_fully_named_list(),
is_all_list_elements_null_or_list(),
is_fully_named_list()
is_all_list_elements_null_or_df(data.frame()) is_all_list_elements_null_or_df(list(data.frame())) is_all_list_elements_null_or_df(list(1, NULL)) is_all_list_elements_null_or_df(list(data.frame(), NULL)) is_all_list_elements_null_or_df(list("a"=1, 2))is_all_list_elements_null_or_df(data.frame()) is_all_list_elements_null_or_df(list(data.frame())) is_all_list_elements_null_or_df(list(1, NULL)) is_all_list_elements_null_or_df(list(data.frame(), NULL)) is_all_list_elements_null_or_df(list("a"=1, 2))
Checks two things: that 'x' is a list, and that all elements in 'x' are 'NULL' or fully named lists.
is_all_list_elements_null_or_fully_named_list(x)is_all_list_elements_null_or_fully_named_list(x)
x |
An object |
A fully named list is a list in which every element has a name.
TRUE or FALSE.
vignette("csutil", package = "csutil"), which runs all four
predicates on small example lists.
Other list predicates:
is_all_list_elements_null_or_df(),
is_all_list_elements_null_or_list(),
is_fully_named_list()
is_all_list_elements_null_or_fully_named_list(data.frame()) is_all_list_elements_null_or_fully_named_list(list(data.frame())) is_all_list_elements_null_or_fully_named_list(list(1, NULL)) is_all_list_elements_null_or_fully_named_list(list(list(), NULL)) is_all_list_elements_null_or_fully_named_list(list(list("a" = 1), NULL)) is_all_list_elements_null_or_fully_named_list(list("a"=1, 2))is_all_list_elements_null_or_fully_named_list(data.frame()) is_all_list_elements_null_or_fully_named_list(list(data.frame())) is_all_list_elements_null_or_fully_named_list(list(1, NULL)) is_all_list_elements_null_or_fully_named_list(list(list(), NULL)) is_all_list_elements_null_or_fully_named_list(list(list("a" = 1), NULL)) is_all_list_elements_null_or_fully_named_list(list("a"=1, 2))
Checks two things: that 'x' is a list, and that all elements in 'x' are 'NULL' or lists.
is_all_list_elements_null_or_list(x)is_all_list_elements_null_or_list(x)
x |
An object |
TRUE or FALSE.
vignette("csutil", package = "csutil"), which runs all four
predicates on small example lists.
Other list predicates:
is_all_list_elements_null_or_df(),
is_all_list_elements_null_or_fully_named_list(),
is_fully_named_list()
is_all_list_elements_null_or_list(data.frame()) is_all_list_elements_null_or_list(list(data.frame())) is_all_list_elements_null_or_list(list(1, NULL)) is_all_list_elements_null_or_list(list(list(), NULL)) is_all_list_elements_null_or_list(list("a"=1, 2))is_all_list_elements_null_or_list(data.frame()) is_all_list_elements_null_or_list(list(data.frame())) is_all_list_elements_null_or_list(list(1, NULL)) is_all_list_elements_null_or_list(list(list(), NULL)) is_all_list_elements_null_or_list(list("a"=1, 2))
Checks if 'x' is a list with each element named.
is_fully_named_list(x)is_fully_named_list(x)
x |
An object |
The empty list is a special case. is_fully_named_list(list()) returns
FALSE, because a fully named list must have at least one element. The
other three predicates in this family return TRUE for list().
TRUE or FALSE.
vignette("csutil", package = "csutil"), which runs all four
predicates on small example lists.
Other list predicates:
is_all_list_elements_null_or_df(),
is_all_list_elements_null_or_fully_named_list(),
is_all_list_elements_null_or_list()
is_fully_named_list(list()) is_fully_named_list(list(1)) is_fully_named_list(list("a"=1)) is_fully_named_list(list("a"=1, 2))is_fully_named_list(list()) is_fully_named_list(list(1)) is_fully_named_list(list("a"=1)) is_fully_named_list(list("a"=1, 2))
Consider a function that returns a list of two data.frames. Call that
function repeatedly and store each return value in a list. You then hold a
list of fully named lists, and each inner list holds a data.frame.
Typically you want the two data.frames out of that nested structure, row-bound
with data.table::rbindlist().
unnest_dfs_within_list_of_fully_named_lists( x, returned_name_when_dfs_are_not_nested = "data", ... )unnest_dfs_within_list_of_fully_named_lists( x, returned_name_when_dfs_are_not_nested = "data", ... )
x |
A list of fully named lists (which then contain data.frames) |
returned_name_when_dfs_are_not_nested |
The name to give the returned
element when |
... |
Parameters passed to |
When every element of x is NULL or a data.frame, the
function row-binds those elements into a single data.table. It
returns that table in a length-1 list, named by
returned_name_when_dfs_are_not_nested.
Otherwise every element of x MUST be NULL or a fully named
list. The function stops with an error if one element is not. The function
names the returned list by the sorted union of the inner names. Each element
is the data.table::rbindlist() of the inner elements that carry that
name.
A fully named list, each element a data.table. NULL if
x is not a list.
vignette("csutil", package = "csutil"), which unnests a
two-element list of fully named lists.
x <- list( list( "a" = data.frame("v1"=1), "b" = data.frame("v2"=3) ), list( "a" = data.frame("v1"=10), "b" = data.frame("v2"=30), "d" = data.frame("v3"=50) ), list( "a" = NULL ), NULL ) print(x) csutil::unnest_dfs_within_list_of_fully_named_lists(x) x <- list( data.frame("v1"=1), data.frame("v3"=50) ) print(x) csutil::unnest_dfs_within_list_of_fully_named_lists( x, returned_name_when_dfs_are_not_nested = "NAME", fill = TRUE )x <- list( list( "a" = data.frame("v1"=1), "b" = data.frame("v2"=3) ), list( "a" = data.frame("v1"=10), "b" = data.frame("v2"=30), "d" = data.frame("v3"=50) ), list( "a" = NULL ), NULL ) print(x) csutil::unnest_dfs_within_list_of_fully_named_lists(x) x <- list( data.frame("v1"=1), data.frame("v3"=50) ) print(x) csutil::unnest_dfs_within_list_of_fully_named_lists( x, returned_name_when_dfs_are_not_nested = "NAME", fill = TRUE )