Title: | Functions for Mapping Key-Value Pairs, Many-to-Many, One-to-Many, and Many-to-One Relations |
---|---|
Description: | Functions to safely map from a vector of keys to a vector of values, determine properties of a given relation, or ensure a relation conforms to a given type, such as many-to-many, one-to-many, injective, surjective, or bijective. Permits default return values for use similar to a vectorised switch statement, as well as safely handling large vectors, NAs, and duplicate mappings. |
Authors: | Dominic Jarkey [aut, cre] |
Maintainer: | Dominic Jarkey <[email protected]> |
License: | MIT + file LICENSE |
Version: | 1.0.0.9000 |
Built: | 2025-03-06 03:18:56 UTC |
Source: | https://github.com/domjarkey/relatable |
A dataset containing atomic numbers, chemical symbols, and names of 118 elements.
elements
elements
A data frame with 118 rows and 3 variables:
Atomic number
Chemical symbol
Name of element
https://en.wikipedia.org/wiki/Symbol_(chemistry)
The relatable
package provides two functions to safely map from a
vector of keys to a vector of values, determine properties of a given
relation, or ensure a relation conforms to a given type, such as
many-to-many, one-to-many, injective, surjective, or bijective. Permits
default return values for use similar to a vectorised switch statement, as
well as safely handling large vectors, NAs, and duplicate mappings.
relate
Returns a vector
where
maps each element of input vector
X
from its position
in vector A
to its corresponding position in vector .
relation
Returns a function that maps each
element of input vector
X
from its position in vector A
to
its corresponding position in vector .
For a quick introduction to the functions of the package see
"Basic Usage" with vignette("relatable-usage")
in R or
online
For instructions on how to use the additional arguments of
relate
and relation
see "Relation Types and Restrictions" with
vignette{"relatable-restrictions"}
in R or
online
relate
returns a vector where
maps
each element of input vector
X
from its position in vector A
to its corresponding position in vector . Can be applied as a
vectorised key-value dictionary with an optional default return value.
Additional options restrict mapping types so relation
must be a
function, injective, surjective, etc.
relation
returns a reusable function that performs the same
operation as
relate
. In addition to providing a reusable function,
if handle_duplicate_mappings = TRUE
, relation
checks for and
eliminates duplicate mappings that would be invalid inputs for
relate
. If report_properties = TRUE
, relation
also
prints the restrictions the mapping from A
to B
conforms to.
relate(X, A, B, default = NA, atomic = TRUE, named = FALSE, allow_default = TRUE, heterogeneous_outputs = FALSE, handle_duplicate_mappings = FALSE, report_properties = FALSE, relation_type = "func", restrictions = list(), map_error_response = "warn") relation(A, B, default = NA, atomic = TRUE, named = FALSE, allow_default = TRUE, heterogeneous_outputs = FALSE, handle_duplicate_mappings = FALSE, report_properties = FALSE, relation_type = "func", restrictions = list(), map_error_response = "warn")
relate(X, A, B, default = NA, atomic = TRUE, named = FALSE, allow_default = TRUE, heterogeneous_outputs = FALSE, handle_duplicate_mappings = FALSE, report_properties = FALSE, relation_type = "func", restrictions = list(), map_error_response = "warn") relation(A, B, default = NA, atomic = TRUE, named = FALSE, allow_default = TRUE, heterogeneous_outputs = FALSE, handle_duplicate_mappings = FALSE, report_properties = FALSE, relation_type = "func", restrictions = list(), map_error_response = "warn")
X |
A vector of inputs |
A |
A vector possible inputs ordered to correspond to desired outputs
given by |
B |
A vector possible outputs ordered to correspond to each input to the
relation given by |
default |
The default value to return if |
atomic |
If |
named |
The elements of the returned vector |
allow_default |
If TRUE, the provided default will be returned when
|
heterogeneous_outputs |
By default, elements |
handle_duplicate_mappings |
If |
report_properties |
If |
relation_type |
Ensure that the relation is restricted to a certain type, e.g. "bijection". See Details. |
restrictions |
A named list of logicals imposing constraints on the
relation. These will only be used if relation_type is |
map_error_response |
How to deal with mapping errors caused by violated restrictions. Takes values "ignore", "warn", or "throw". |
relate
returns vector of outputs where the
is a relation defined by the collection of ordered pairs
where
are the
th elements of
A
and
B
respectively. If is undefined because
is not in
or it does not map to an element of
B
, relate
will
either return default
if allow_default = TRUE
. Otherwise the
function will throw an error.
The relation can be restricted so it conforms to a particular type
specified by
relation_type
. If relation_type = NULL
, the
properties are determined by restrictions specified with a named list, for
example restrictions = list(min_one_y_per_x = TRUE)
. For all
relations where min_one_y_per_x = FALSE
, only a list vector can be
returned, so an error will be thrown if atomic = TRUE
. If A
and B
do not produce a relation that conforms to the specified type
or restrictions, the value of map_error_response
will determine
whether the relate
ignores the error, reports it, or throws it. The
full list of restrictions and relation types are listed below:
Restrictions
NB: 1) The restrictions
argument is only used if
relation_type = NULL
; 2) If relation is allowed to return multiple
values, i.e. max_one_y_per_x = FALSE
, then atomic
must be set
to FALSE
, otherwise an error will be throw; 3). All unspecified
restrictions are assumed false, e.g. restrictions = list()
is
equivalent to restrictions = list("min_one_y_per_x" = FALSE,
"min_one_x_per_y" = FALSE, "max_one_y_per_x" = FALSE, "max_one_x_per_y" =
FALSE)
min_one_y_per_x
Guarantees at least one
in
B
exists for each in
A
. Returns an
error if B is longer than A.
min_one_x_per_y
Guarantees at
least one in
A
exists for each in
B
such that
. Returns an error if A is longer than B.
max_one_y_per_x
Guarantees no more than one in
B
exists for each in
A
. Returns an error if A
contains duplicate elements.
max_one_x_per_y
Guarantees no
more than one in
A
exists for each in
B
such
that . Returns an error if B contains duplicate elements.
Relation types
relation_type =
"one_to_one"
One-to-one relations require that each element in the domain
to map to at most one element in the codomain, and each element of the
codomain to map from the only one element in the domain. There may still be
elements in A
that do not have a mapping to an element in B
,
and vice versa. This is equivalent to
restrictions =
list(
"min_one_y_per_x" = FALSE,
"min_one_x_per_y" = FALSE,
"max_one_y_per_x"
= TRUE,
"max_one_x_per_y" = TRUE
relation_type = "many_to_many"
Many-to-many relations allow multiple elements in the domain to map to the same element of the codomain, and multiple elements of the codomain to map from the same element of the domain. This is equivalent to
restrictions =
list(
"min_one_y_per_x" = FALSE,
"min_one_x_per_y" = FALSE,
"max_one_y_per_x"
= FALSE,
"max_one_x_per_y" = FALSE
relation_type = "one_to_many"
One-to-many relations require each element of the domain to map to a distinct set of one or more elements in the codomain. This is equivalent to
restrictions
= list(
"min_one_y_per_x" = FALSE,
"min_one_x_per_y" = FALSE,
"max_one_y_per_x"
= FALSE,
"max_one_x_per_y" = TRUE
relation_type = "many_to_one"
Many-to-one relations allows sets of one or more elements in the domain to map to the same distinct element in the codomain. This is equivalent to
restrictions = list(
"min_one_y_per_x" = FALSE,
"min_one_x_per_y"
= FALSE,
"max_one_y_per_x" = TRUE,
"max_one_x_per_y" = FALSE
relation_type = "func"
Functions map each element in the domain to exactly one element in the codomain. This is equivalent to
restrictions = list(
"min_one_y_per_x" = TRUE,
"min_one_x_per_y" =
FALSE,
"max_one_y_per_x" = TRUE,
"max_one_x_per_y" = FALSE
relation_type = "injection"
A function is injective if every element of the domain maps to a unique element of the codomain. This is equivalent to
restrictions = list(
"min_one_y_per_x" = TRUE,
"min_one_x_per_y" =
FALSE,
"max_one_y_per_x" = TRUE,
"max_one_x_per_y" = TRUE
relation_type = "surjection"
A function is surjective if every element of the codomain maps from an element of the domain. This is equivalent to
restrictions = list(
"min_one_y_per_x" = TRUE,
"min_one_x_per_y" =
TRUE,
"max_one_y_per_x" = TRUE,
"max_one_x_per_y" = FALSE
relation_type = "bijection"
A function is bijective if it is both injective and surjective, i.e. a complete one-to-one mapping. This is equivalent to
restrictions = list(
"min_one_y_per_x" = TRUE,
"min_one_x_per_y" =
TRUE,
"max_one_y_per_x" = TRUE,
"max_one_x_per_y" = TRUE
## Map from one vector to another relate(c("a", "e", "i", "o", "u"), letters, LETTERS) # [1] "A" "E" "I" "O" "U" ## or caps <- relation(letters, LETTERS) caps("t") # [1] "T" caps(c("p", "q", "r")) # [1] "P" "Q" "R" ## Create a new column in a data frame df <- data.frame( name = c("Alice", "Bob", "Charlotte", "Dan", "Elise", "Frank"), position = c("right", "lean-left", "left", "left", "lean-right", "no response") ) positions <- c("left", "lean-left", "independent", "lean-right", "right") colours <- c("darkblue", "lightblue", "green", "lightred", "darkred") df$colour <- relate(df$position, positions, colours, default = "gray") df # name position colour # 1 Alice right darkred # 2 Bob lean-left lightblue # 3 Charlotte left darkblue # 4 Dan left darkblue # 5 Elise lean-right lightred # 6 Frank no response gray ## Authors have a many-to-many relation with books: ## a book can have multiple authors and authors can write multiple books my_library <- data.frame( author = c( "Arendt", "Austen-Smith", "Austen-Smith", "Austen-Smith", "Banks", "Banks", "Camus", "Camus", "Arendt", "Dryzek", "Dunleavy" ), work = c( "The Human Condition", "Social Choice and Voting Models", "Information Aggregation, Rationality, and the Condorcet Jury Theorem", "Positive Political Theory I", "Information Aggregation, Rationality, and the Condorcet Jury Theorem", "Positive Political Theory I", "The Myth of Sisyphus", "The Rebel", "The Origins of Totalitarianism", "Theories of the Democratic State", "Theories of the Democratic State" ), stringsAsFactors = FALSE ) relate( X = c("Arendt", "Austen-Smith", "Banks", "Dryzek", "Dunleavy"), A = my_library$author, B = my_library$work, atomic = FALSE, named = TRUE, relation_type = "many_to_many" ) # $Arendt # [1] "The Human Condition" "The Origins of Totalitarianism" # # $`Austen-Smith` # [1] "Social Choice and Voting Models" # [2] "Information Aggregation, Rationality, and the Condorcet Jury Theorem" # [3] "Positive Political Theory I" # # $Banks # [1] "Information Aggregation, Rationality, and the Condorcet Jury Theorem" # [2] "Positive Political Theory I" # # $Dryzek # [1] "Theories of the Democratic State" # # $Dunleavy # [1] "Theories of the Democratic State" ## Duplicate mappings will return multiple copies by default: relate( X = 1:3, A = c(1, 2, 2, 3, 4, 5), B = c('a', 'b', 'b', 'c', 'd', 'e'), relation_type = "many_to_many", atomic = FALSE ) # [[1]] # [1] "a" # # [[2]] # [1] "b" "b" # # [[3]] # [1] "c" ## Use handle_duplicate_mappings = TRUE to ignore these and avoid mapping errors. nums_to_letters <- relation( A = c(1, 2, 2, 3, 4, 5), B = c('a', 'b', 'b', 'c', 'd', 'e'), relation_type = "bijection", handle_duplicate_mappings = TRUE ) nums_to_letters(X = c(1, 2, 3)) # [1] "a" "b" "c" ## Use relation with report_properties = TRUE to determine the properties of specified relation domain <- -3:3 image <- domain^2 relation(domain, image, report_properties = TRUE) # Relation properties: # min_one_y_per_x min_one_x_per_y max_one_y_per_x max_one_x_per_y # TRUE TRUE TRUE FALSE
## Map from one vector to another relate(c("a", "e", "i", "o", "u"), letters, LETTERS) # [1] "A" "E" "I" "O" "U" ## or caps <- relation(letters, LETTERS) caps("t") # [1] "T" caps(c("p", "q", "r")) # [1] "P" "Q" "R" ## Create a new column in a data frame df <- data.frame( name = c("Alice", "Bob", "Charlotte", "Dan", "Elise", "Frank"), position = c("right", "lean-left", "left", "left", "lean-right", "no response") ) positions <- c("left", "lean-left", "independent", "lean-right", "right") colours <- c("darkblue", "lightblue", "green", "lightred", "darkred") df$colour <- relate(df$position, positions, colours, default = "gray") df # name position colour # 1 Alice right darkred # 2 Bob lean-left lightblue # 3 Charlotte left darkblue # 4 Dan left darkblue # 5 Elise lean-right lightred # 6 Frank no response gray ## Authors have a many-to-many relation with books: ## a book can have multiple authors and authors can write multiple books my_library <- data.frame( author = c( "Arendt", "Austen-Smith", "Austen-Smith", "Austen-Smith", "Banks", "Banks", "Camus", "Camus", "Arendt", "Dryzek", "Dunleavy" ), work = c( "The Human Condition", "Social Choice and Voting Models", "Information Aggregation, Rationality, and the Condorcet Jury Theorem", "Positive Political Theory I", "Information Aggregation, Rationality, and the Condorcet Jury Theorem", "Positive Political Theory I", "The Myth of Sisyphus", "The Rebel", "The Origins of Totalitarianism", "Theories of the Democratic State", "Theories of the Democratic State" ), stringsAsFactors = FALSE ) relate( X = c("Arendt", "Austen-Smith", "Banks", "Dryzek", "Dunleavy"), A = my_library$author, B = my_library$work, atomic = FALSE, named = TRUE, relation_type = "many_to_many" ) # $Arendt # [1] "The Human Condition" "The Origins of Totalitarianism" # # $`Austen-Smith` # [1] "Social Choice and Voting Models" # [2] "Information Aggregation, Rationality, and the Condorcet Jury Theorem" # [3] "Positive Political Theory I" # # $Banks # [1] "Information Aggregation, Rationality, and the Condorcet Jury Theorem" # [2] "Positive Political Theory I" # # $Dryzek # [1] "Theories of the Democratic State" # # $Dunleavy # [1] "Theories of the Democratic State" ## Duplicate mappings will return multiple copies by default: relate( X = 1:3, A = c(1, 2, 2, 3, 4, 5), B = c('a', 'b', 'b', 'c', 'd', 'e'), relation_type = "many_to_many", atomic = FALSE ) # [[1]] # [1] "a" # # [[2]] # [1] "b" "b" # # [[3]] # [1] "c" ## Use handle_duplicate_mappings = TRUE to ignore these and avoid mapping errors. nums_to_letters <- relation( A = c(1, 2, 2, 3, 4, 5), B = c('a', 'b', 'b', 'c', 'd', 'e'), relation_type = "bijection", handle_duplicate_mappings = TRUE ) nums_to_letters(X = c(1, 2, 3)) # [1] "a" "b" "c" ## Use relation with report_properties = TRUE to determine the properties of specified relation domain <- -3:3 image <- domain^2 relation(domain, image, report_properties = TRUE) # Relation properties: # min_one_y_per_x min_one_x_per_y max_one_y_per_x max_one_x_per_y # TRUE TRUE TRUE FALSE
A dataset containing names of US states and their abbreviations under various standards including ANSI, ISO, USPS, USCG, GPO, Associated Press.
US_states
US_states
A data frame with 51 rows and 10 variables:
US Region Name
State, State (Commonwealth), or Federal District
State Capital
American National Standards Institute 2-letter code
American National Standards Institute 2-digit code. This is stored as a character to ensure all entries are two characters long
International Organization for Standardization 3166-2 code for US States
United States Postal Service 2-letter code
United States Coast Guard 2-letter code (used as prefices for vessel numbers)
US Government Printing Office abbreviations
Associated Press Stylebook abbreviations
https://en.wikipedia.org/wiki/List_of_U.S._state_abbreviations