rrapply is a reimplemented and extended version of rapply to recursively apply a function f to a set of elements of a list and deciding how the result is structured.

rrapply(
  object,
  condition,
  f,
  classes = "ANY",
  deflt = NULL,
  how = c("replace", "list", "unlist", "prune", "flatten", "melt", "bind", "recurse",
    "unmelt"),
  feverywhere,
  dfaslist,
  ...
)

Arguments

object

a list, expression vector, or call object, i.e., “list-like”.

condition

a condition function of one “principal” argument and optional special arguments .xname, .xpos, .xparents and/or .xsiblings (see ‘Details’), passing further arguments via ....

f

a function of one “principal” argument and optional special arguments .xname, .xpos, .xparents and/or .xsiblings (see ‘Details’), passing further arguments via ....

classes

character vector of class names, or "ANY" to match the class of any terminal node. Include "list" or "data.frame" to match the class of non-terminal nodes as well.

deflt

the default result (only used if how = "list" or how = "unlist").

how

character string partially matching the nine possibilities given: see ‘Details’.

feverywhere

deprecated use classes = "list", classes = "language" or classes = "expression" and optionally how = "recurse" instead.

dfaslist

deprecated use classes = "data.frame" instead.

...

additional arguments passed to the call to f and condition.

Value

If how = "unlist", a vector as in rapply. If how = "list", how = "replace" or how = "recurse", “list-like” of similar structure as object as in rapply. If how = "prune", a pruned “list-like” object of similar structure as object with pruned list elements based on classes and condition. If how = "flatten", a flattened pruned vector or list with pruned elements based on classes and condition. The result of how = "flatten" is coerced to vector similar to how = "unlist". If how = "melt", a melted data.frame containing the node paths and values of the pruned list elements based on classes and condition. If how = "unmelt", a nested list with list names and values defined in the data.frame object.

Note

rrapply allows the f function argument to be missing, in which case no function is applied to the list elements.

how = "unmelt" requires as input a data.frame as returned by how = "melt" with character columns to name the nested list components and a final list- or vector-column containing the values of the nested list elements.

How to structure result

In addition to rapply's modes to set how equal to "replace", "list" or "unlist", five choices "prune", "flatten", "melt", "bind", "unmelt" and "recurse" are available. how = "prune" filters all list elements not subject to application of f from the list object. The original list structure is retained, similar to the non-pruned options how = "replace" or how = "list". how = "flatten" is an efficient way to return a flattened unnested version of the pruned list. how = "flatten" uses similar coercion rules as how = "unlist". how = "melt" returns a melted data.frame of the pruned list, each row contains the path of a single terminal node in the pruned list at depth layers L1, L2, and so on. The column "value" contains the possible coerced values at the terminal nodes and is equivalent to the result of how = "flatten". If no list names are present, the node names in the data.frame default to the indices of the list elements "1", "2", etc. how = "bind" is used to unnest a nested list containing repeated sublists into a wide data.frame. Each repeated sublist is expanded as a single row in the data.frame and identical names between sublists are aligned as individual columns. Repeated sublists are recognized as several sublists on the same nested level that are either unnamed or have the same name for each sublist. how = "unmelt" is a special case that reconstructs a nested list from a melted data.frame. For this reason, how = "unmelt" only applies to data.frames in the same format as returned by how = "melt". Internally, how = "unmelt" first reconstructs a nested list from the melted data.frame and second uses the same framework as how = "replace". how = "recurse" is a specialized option that is only useful in combination with e.g. classes = "list" to recurse further into updated “list-like” elements. This is explained in more detail below.

Condition function

Both rapply and rrapply allow to apply f to list elements of certain classes via the classes argument. rrapply generalizes this concept via an additional condition argument, which accepts any function to use as a condition or predicate to select list elements to which f is applied. Conceptually, the f function is applied to all list elements for which the condition function exactly evaluates to TRUE similar to isTRUE. If the condition function is missing, f is applied to all list elements. Since the condition function generalizes the classes argument, it is allowed to use the deflt argument together with how = "list" or how = "unlist" to set a default value to all list elements for which the condition does not evaluate to TRUE.

Correct use of ...

The principal argument of the f and condition functions evaluates to the content of the list element. Any further arguments to f and condition (besides the special arguments .xname and .xpos discussed below) supplied via the dots ... argument need to be defined as function arguments in both the f and condition function (if existing), even if they are not used in the function itself. See also the ‘Examples’ section.

Special arguments .xname, .xpos, .xparents and .xsiblings

The f and condition functions accept four special arguments .xname, .xpos, .xparents and .xsiblings in addition to the first principal argument. The .xname argument evaluates to the name of the list element. The .xpos argument evaluates to the position of the element in the nested list structured as an integer vector. That is, if x = list(list("y", "z")), then an .xpos location of c(1, 2) corresponds to the list element x[[c(1, 2)]]. The .xparents argument evaluates to a vector of all parent node names in the path to the list element. The .xsiblings argument evaluates to the complete (sub)list that includes the list element as a direct child. The names .xname, .xpos, .xparents or .xsiblings need to be explicitly included as function arguments in f and condition (in addition to the principal argument). See the package vignette for example uses of these special variables.

Avoid recursing into list nodes

By default, rrapply recurses into any “list-like” element. If classes = "list", this behavior is overridden and the f function is also applied to any list element of object that satisfies condition. For expression objects, use classes = "language", classes = "expression" or classes = "pairlist" to avoid recursing into branches of the abstract syntax tree of object. If the condition or classes arguments are not satisfied for a “list-like” element, rrapply will recurse further into the sublist, apply the f function to the nodes that satisfy condition and classes, and so on. Note that this behavior can only be triggered using the classes argument and not the condition argument.

Recursive list node updating

If classes = "list" and how = "recurse", rrapply applies the f function to any list element of object that satisfies condition similar to the previous section using how = "replace", but recurses further into the updated list-like element after application of the f function. The primary use of how = "recurse" in combination with classes = "list" is to recursively update for instance the names of all nodes in a nested list. Additional examples are found in the package vignette.

Avoid recursing into data.frames

If classes = "ANY" (default), rrapply recurses into all “list-like” objects equivalent to rapply. Since data.frames are “list-like” objects, the f function will descend into the individual columns of a data.frame. To avoid this behavior, set classes = "data.frame", in which case the f and condition functions are applied directly to the data.frame and not its columns. Note that this behavior can only be triggered using the classes argument and not the condition argument.

List attributes

In rapply intermediate list attributes (not located at terminal nodes) are kept when how = "replace", but are dropped when how = "list". To avoid unexpected behavior, rrapply always preserves intermediate list attributes when using how = "replace", how = "list" or how = "prune". If how = "flatten" or how = "unlist" intermediate list attributes cannot be preserved as the result is no longer a nested list.

Expressions

Call objects and expression vectors are also accepted as object argument, which are treated as nested lists based on their internal abstract syntax trees. As such, all functionality that applies to nested lists extends directly to call objects and expression vectors. If object is a call object or expression vector, how = "replace" always maintains the type of object, whereas how = "list" returns the result structured as a nested list. how = "prune", how = "flatten" and how = "melt" return the pruned abstract syntax tree as: a nested list, a flattened list and a melted data.frame respectively. This is identical to application of rrapply to the abstract syntax tree formatted as a nested list.

See also

Examples

# Example data ## Nested list of renewable energy (%) of total energy consumption per country in 2016 data("renewable_energy_by_country") ## Subset values for countries and areas in Oceania renewable_oceania <- renewable_energy_by_country[["World"]]["Oceania"] ## Nested list of Pokemon properties in Pokemon GO data("pokedex") # List pruning and unnesting ## Drop all logical NA's while preserving list structure na_drop_oceania <- rrapply( renewable_oceania, f = function(x) x, classes = "numeric", how = "prune" ) str(na_drop_oceania, list.len = 3, give.attr = FALSE)
#> List of 1 #> $ Oceania:List of 4 #> ..$ Australia and New Zealand:List of 2 #> .. ..$ Australia : num 9.32 #> .. ..$ New Zealand: num 32.8 #> ..$ Melanesia :List of 5 #> .. ..$ Fiji : num 24.4 #> .. ..$ New Caledonia : num 4.03 #> .. ..$ Papua New Guinea: num 50.3 #> .. .. [list output truncated] #> ..$ Micronesia :List of 7 #> .. ..$ Guam : num 3.03 #> .. ..$ Kiribati : num 45.4 #> .. ..$ Marshall Islands : num 11.8 #> .. .. [list output truncated] #> .. [list output truncated]
## Drop all logical NA's and return unnested list na_drop_oceania2 <- rrapply( renewable_oceania, f = function(x) x, classes = "numeric", how = "flatten" ) head(na_drop_oceania2, n = 10)
#> Australia New Zealand Fiji New Caledonia #> 9.32 32.76 24.36 4.03 #> Papua New Guinea Solomon Islands Vanuatu Guam #> 50.34 65.73 33.67 3.03 #> Kiribati Marshall Islands #> 45.43 11.75
## Drop all logical NA's and return melted data.frame na_drop_oceania3 <- rrapply( renewable_oceania, f = identity, classes = "numeric", how = "melt" ) head(na_drop_oceania3)
#> L1 L2 L3 value #> 1 Oceania Australia and New Zealand Australia 9.32 #> 2 Oceania Australia and New Zealand New Zealand 32.76 #> 3 Oceania Melanesia Fiji 24.36 #> 4 Oceania Melanesia New Caledonia 4.03 #> 5 Oceania Melanesia Papua New Guinea 50.34 #> 6 Oceania Melanesia Solomon Islands 65.73
## Reconstruct nested list from melted data.frame na_drop_oceania4 <- rrapply( na_drop_oceania3, how = "unmelt" ) str(na_drop_oceania4, list.len = 3, give.attr = FALSE)
#> List of 1 #> $ Oceania:List of 4 #> ..$ Australia and New Zealand:List of 2 #> .. ..$ Australia : num 9.32 #> .. ..$ New Zealand: num 32.8 #> ..$ Melanesia :List of 5 #> .. ..$ Fiji : num 24.4 #> .. ..$ New Caledonia : num 4.03 #> .. ..$ Papua New Guinea: num 50.3 #> .. .. [list output truncated] #> ..$ Micronesia :List of 7 #> .. ..$ Guam : num 3.03 #> .. ..$ Kiribati : num 45.4 #> .. ..$ Marshall Islands : num 11.8 #> .. .. [list output truncated] #> .. [list output truncated]
## Convert nested list to wide data.frame pokedex_wide <- rrapply(pokedex, how = "bind") head(pokedex_wide)
#> pokemon.id pokemon.num pokemon.name #> 1 1 001 Bulbasaur #> 2 2 002 Ivysaur #> 3 3 003 Venusaur #> 4 4 004 Charmander #> 5 5 005 Charmeleon #> 6 6 006 Charizard #> pokemon.img pokemon.type pokemon.height #> 1 http://www.serebii.net/pokemongo/pokemon/001.png Grass, Poison 0.71 m #> 2 http://www.serebii.net/pokemongo/pokemon/002.png Grass, Poison 0.99 m #> 3 http://www.serebii.net/pokemongo/pokemon/003.png Grass, Poison 2.01 m #> 4 http://www.serebii.net/pokemongo/pokemon/004.png Fire 0.61 m #> 5 http://www.serebii.net/pokemongo/pokemon/005.png Fire 1.09 m #> 6 http://www.serebii.net/pokemongo/pokemon/006.png Fire, Flying 1.70 m #> pokemon.weight pokemon.candy pokemon.candy_count pokemon.egg #> 1 6.9 kg Bulbasaur Candy 25 2 km #> 2 13.0 kg Bulbasaur Candy 100 Not in Eggs #> 3 100.0 kg Bulbasaur Candy NA Not in Eggs #> 4 8.5 kg Charmander Candy 25 2 km #> 5 19.0 kg Charmander Candy 100 Not in Eggs #> 6 90.5 kg Charmander Candy NA Not in Eggs #> pokemon.spawn_chance pokemon.avg_spawns pokemon.spawn_time #> 1 0.6900 69.00 20:00 #> 2 0.0420 4.20 07:00 #> 3 0.0170 1.70 11:30 #> 4 0.2530 25.30 08:45 #> 5 0.0120 1.20 19:00 #> 6 0.0031 0.31 13:34 #> pokemon.multipliers pokemon.weaknesses pokemon.next_evolution.1.num #> 1 1.58 Fire, Ice, Flying, Psychic 002 #> 2 1.2, 1.6 Fire, Ice, Flying, Psychic 003 #> 3 NA Fire, Ice, Flying, Psychic <NA> #> 4 1.65 Water, Ground, Rock 005 #> 5 1.79 Water, Ground, Rock 006 #> 6 NA Water, Electric, Rock <NA> #> pokemon.next_evolution.1.name pokemon.next_evolution.2.num #> 1 Ivysaur 003 #> 2 Venusaur <NA> #> 3 <NA> <NA> #> 4 Charmeleon 006 #> 5 Charizard <NA> #> 6 <NA> <NA> #> pokemon.next_evolution.2.name pokemon.prev_evolution.1.num #> 1 Venusaur <NA> #> 2 <NA> 001 #> 3 <NA> 001 #> 4 Charizard <NA> #> 5 <NA> 004 #> 6 <NA> 004 #> pokemon.prev_evolution.1.name pokemon.prev_evolution.2.num #> 1 <NA> <NA> #> 2 Bulbasaur <NA> #> 3 Bulbasaur 002 #> 4 <NA> <NA> #> 5 Charmander <NA> #> 6 Charmander 005 #> pokemon.prev_evolution.2.name pokemon.next_evolution.3.num #> 1 <NA> <NA> #> 2 <NA> <NA> #> 3 Ivysaur <NA> #> 4 <NA> <NA> #> 5 <NA> <NA> #> 6 Charmeleon <NA> #> pokemon.next_evolution.3.name #> 1 <NA> #> 2 <NA> #> 3 <NA> #> 4 <NA> #> 5 <NA> #> 6 <NA>
# Condition function ## Drop all NA elements using condition function na_drop_oceania3 <- rrapply( renewable_oceania, condition = Negate(is.na), f = function(x) x, how = "prune" ) str(na_drop_oceania3, list.len = 3, give.attr = FALSE)
#> List of 1 #> $ Oceania:List of 4 #> ..$ Australia and New Zealand:List of 2 #> .. ..$ Australia : num 9.32 #> .. ..$ New Zealand: num 32.8 #> ..$ Melanesia :List of 5 #> .. ..$ Fiji : num 24.4 #> .. ..$ New Caledonia : num 4.03 #> .. ..$ Papua New Guinea: num 50.3 #> .. .. [list output truncated] #> ..$ Micronesia :List of 7 #> .. ..$ Guam : num 3.03 #> .. ..$ Kiribati : num 45.4 #> .. ..$ Marshall Islands : num 11.8 #> .. .. [list output truncated] #> .. [list output truncated]
## Replace NA elements by a new value via the ... argument ## NB: the 'newvalue' argument should be present as function ## argument in both 'f' and 'condition', even if unused. na_zero_oceania <- rrapply( renewable_oceania, condition = function(x, newvalue) is.na(x), f = function(x, newvalue) newvalue, newvalue = 0, how = "replace" ) str(na_zero_oceania, list.len = 3, give.attr = FALSE)
#> List of 1 #> $ Oceania:List of 4 #> ..$ Australia and New Zealand:List of 6 #> .. ..$ Australia : num 9.32 #> .. ..$ Christmas Island : num 0 #> .. ..$ Cocos (Keeling) Islands : num 0 #> .. .. [list output truncated] #> ..$ Melanesia :List of 5 #> .. ..$ Fiji : num 24.4 #> .. ..$ New Caledonia : num 4.03 #> .. ..$ Papua New Guinea: num 50.3 #> .. .. [list output truncated] #> ..$ Micronesia :List of 8 #> .. ..$ Guam : num 3.03 #> .. ..$ Kiribati : num 45.4 #> .. ..$ Marshall Islands : num 11.8 #> .. .. [list output truncated] #> .. [list output truncated]
## Filter all countries with values above 85% renewable_energy_above_85 <- rrapply( renewable_energy_by_country, condition = function(x) x > 85, how = "prune" ) str(renewable_energy_above_85, give.attr = FALSE)
#> List of 1 #> $ World:List of 1 #> ..$ Africa:List of 1 #> .. ..$ Sub-Saharan Africa:List of 3 #> .. .. ..$ Eastern Africa:List of 7 #> .. .. .. ..$ Burundi : num 89.2 #> .. .. .. ..$ Ethiopia : num 91.9 #> .. .. .. ..$ Rwanda : num 86 #> .. .. .. ..$ Somalia : num 94.7 #> .. .. .. ..$ Uganda : num 88.6 #> .. .. .. ..$ United Republic of Tanzania: num 86.1 #> .. .. .. ..$ Zambia : num 88.5 #> .. .. ..$ Middle Africa :List of 2 #> .. .. .. ..$ Chad : num 85.3 #> .. .. .. ..$ Democratic Republic of the Congo: num 97 #> .. .. ..$ Western Africa:List of 1 #> .. .. .. ..$ Guinea-Bissau: num 86.5
# Special arguments .xname, .xpos, .xparents and .xsiblings ## Apply a function using the name of the node renewable_oceania_text <- rrapply( renewable_oceania, f = function(x, .xname) sprintf("Renewable energy in %s: %.2f%%", .xname, x), condition = Negate(is.na), how = "flatten" ) head(renewable_oceania_text, n = 10)
#> Australia #> "Renewable energy in Australia: 9.32%" #> New Zealand #> "Renewable energy in New Zealand: 32.76%" #> Fiji #> "Renewable energy in Fiji: 24.36%" #> New Caledonia #> "Renewable energy in New Caledonia: 4.03%" #> Papua New Guinea #> "Renewable energy in Papua New Guinea: 50.34%" #> Solomon Islands #> "Renewable energy in Solomon Islands: 65.73%" #> Vanuatu #> "Renewable energy in Vanuatu: 33.67%" #> Guam #> "Renewable energy in Guam: 3.03%" #> Kiribati #> "Renewable energy in Kiribati: 45.43%" #> Marshall Islands #> "Renewable energy in Marshall Islands: 11.75%"
## Extract values based on country names renewable_benelux <- rrapply( renewable_energy_by_country, condition = function(x, .xname) .xname %in% c("Belgium", "Netherlands", "Luxembourg"), how = "prune" ) str(renewable_benelux, give.attr = FALSE)
#> List of 1 #> $ World:List of 1 #> ..$ Europe:List of 1 #> .. ..$ Western Europe:List of 3 #> .. .. ..$ Belgium : num 9.14 #> .. .. ..$ Luxembourg : num 13.5 #> .. .. ..$ Netherlands: num 5.78
## Filter European countries with value above 50% renewable_europe_above_50 <- rrapply( renewable_energy_by_country, condition = function(x, .xpos) identical(.xpos[c(1, 2)], c(1L, 5L)) & x > 50, how = "prune" ) str(renewable_europe_above_50, give.attr = FALSE)
#> List of 1 #> $ World:List of 1 #> ..$ Europe:List of 2 #> .. ..$ Northern Europe:List of 3 #> .. .. ..$ Iceland: num 78.1 #> .. .. ..$ Norway : num 59.5 #> .. .. ..$ Sweden : num 51.4 #> .. ..$ Western Europe :List of 1 #> .. .. ..$ Liechtenstein: num 62.9
## Filter European countries with value above 50% renewable_europe_above_50 <- rrapply( renewable_energy_by_country, condition = function(x, .xparents) "Europe" %in% .xparents & x > 50, how = "prune" ) str(renewable_europe_above_50, give.attr = FALSE)
#> List of 1 #> $ World:List of 1 #> ..$ Europe:List of 2 #> .. ..$ Northern Europe:List of 3 #> .. .. ..$ Iceland: num 78.1 #> .. .. ..$ Norway : num 59.5 #> .. .. ..$ Sweden : num 51.4 #> .. ..$ Western Europe :List of 1 #> .. .. ..$ Liechtenstein: num 62.9
## Return position of Sweden in list (xpos_sweden <- rrapply( renewable_energy_by_country, condition = function(x, .xname) identical(.xname, "Sweden"), f = function(x, .xpos) .xpos, how = "flatten" ))
#> $Sweden #> [1] 1 5 2 14 #>
renewable_energy_by_country[[xpos_sweden$Sweden]]
#> [1] 51.35 #> attr(,"M49-code") #> [1] "752"
## Return siblings of Sweden in list siblings_sweden <- rrapply( renewable_energy_by_country, condition = function(x, .xsiblings) "Sweden" %in% names(.xsiblings), how = "flatten" ) head(siblings_sweden, n = 10)
#> Aland Islands Denmark Estonia Faroe Islands Finland #> NA 33.06 26.55 4.24 42.03 #> Iceland Ireland Isle of Man Latvia Lithuania #> 78.07 8.65 4.30 38.48 31.42
## Return wide Pokedex data.frame without evolutions pokedex_small <- rrapply( pokedex, condition = function(x, .xparents) !any(grepl("evolution", .xparents)), how = "bind" ) head(pokedex_small)
#> pokemon.id pokemon.num pokemon.name #> 1 1 001 Bulbasaur #> 2 2 002 Ivysaur #> 3 3 003 Venusaur #> 4 4 004 Charmander #> 5 5 005 Charmeleon #> 6 6 006 Charizard #> pokemon.img pokemon.type pokemon.height #> 1 http://www.serebii.net/pokemongo/pokemon/001.png Grass, Poison 0.71 m #> 2 http://www.serebii.net/pokemongo/pokemon/002.png Grass, Poison 0.99 m #> 3 http://www.serebii.net/pokemongo/pokemon/003.png Grass, Poison 2.01 m #> 4 http://www.serebii.net/pokemongo/pokemon/004.png Fire 0.61 m #> 5 http://www.serebii.net/pokemongo/pokemon/005.png Fire 1.09 m #> 6 http://www.serebii.net/pokemongo/pokemon/006.png Fire, Flying 1.70 m #> pokemon.weight pokemon.candy pokemon.candy_count pokemon.egg #> 1 6.9 kg Bulbasaur Candy 25 2 km #> 2 13.0 kg Bulbasaur Candy 100 Not in Eggs #> 3 100.0 kg Bulbasaur Candy NA Not in Eggs #> 4 8.5 kg Charmander Candy 25 2 km #> 5 19.0 kg Charmander Candy 100 Not in Eggs #> 6 90.5 kg Charmander Candy NA Not in Eggs #> pokemon.spawn_chance pokemon.avg_spawns pokemon.spawn_time #> 1 0.6900 69.00 20:00 #> 2 0.0420 4.20 07:00 #> 3 0.0170 1.70 11:30 #> 4 0.2530 25.30 08:45 #> 5 0.0120 1.20 19:00 #> 6 0.0031 0.31 13:34 #> pokemon.multipliers pokemon.weaknesses #> 1 1.58 Fire, Ice, Flying, Psychic #> 2 1.2, 1.6 Fire, Ice, Flying, Psychic #> 3 NA Fire, Ice, Flying, Psychic #> 4 1.65 Water, Ground, Rock #> 5 1.79 Water, Ground, Rock #> 6 NA Water, Electric, Rock
# Modifying list elements ## Calculate mean value of Europe rrapply( renewable_energy_by_country, classes = "list", condition = function(x, .xname) .xname == "Europe", f = function(x) mean(unlist(x), na.rm = TRUE), how = "flatten" )
#> Europe #> 22.36565
## Calculate mean value for each continent renewable_continent_summary <- rrapply( renewable_energy_by_country, classes = "list", condition = function(x, .xpos) length(.xpos) == 2, f = function(x) mean(unlist(x), na.rm = TRUE) ) ## Antarctica's value is missing str(renewable_continent_summary, give.attr = FALSE)
#> List of 1 #> $ World:List of 6 #> ..$ Africa : num 54.3 #> ..$ Americas : num 18.2 #> ..$ Antarctica: logi NA #> ..$ Asia : num 17.9 #> ..$ Europe : num 22.4 #> ..$ Oceania : num 17.8
# List node updating ## replace country names by M-49 codes renewable_M49 <- rrapply( list(renewable_energy_by_country), classes = "list", f = function(x) { names(x) <- vapply(x, attr, character(1L), which = "M49-code") return(x) }, how = "recurse" ) str(renewable_M49[[1]], max.level = 3, list.len = 3, give.attr = FALSE)
#> List of 1 #> $ 001:List of 6 #> ..$ 002:List of 2 #> .. ..$ 015:List of 7 #> .. ..$ 202:List of 4 #> ..$ 019:List of 2 #> .. ..$ 419:List of 3 #> .. ..$ 021:List of 5 #> ..$ 010: logi NA #> .. [list output truncated]
# List attributes ## how = "list" preserves all list attributes na_drop_oceania_attr <- rrapply( renewable_oceania, f = function(x) replace(x, is.na(x), 0), how = "list" ) str(na_drop_oceania_attr, max.level = 2)
#> List of 1 #> $ Oceania:List of 4 #> ..$ Australia and New Zealand:List of 6 #> .. ..- attr(*, "M49-code")= chr "053" #> ..$ Melanesia :List of 5 #> .. ..- attr(*, "M49-code")= chr "054" #> ..$ Micronesia :List of 8 #> .. ..- attr(*, "M49-code")= chr "057" #> ..$ Polynesia :List of 10 #> .. ..- attr(*, "M49-code")= chr "061" #> ..- attr(*, "M49-code")= chr "009"
## how = "prune" also preserves list attributes na_drop_oceania_attr2 <- rrapply( renewable_oceania, condition = Negate(is.na), how = "prune" ) str(na_drop_oceania_attr2, max.level = 2)
#> List of 1 #> $ Oceania:List of 4 #> ..$ Australia and New Zealand:List of 2 #> .. ..- attr(*, "M49-code")= chr "053" #> ..$ Melanesia :List of 5 #> .. ..- attr(*, "M49-code")= chr "054" #> ..$ Micronesia :List of 7 #> .. ..- attr(*, "M49-code")= chr "057" #> ..$ Polynesia :List of 8 #> .. ..- attr(*, "M49-code")= chr "061" #> ..- attr(*, "M49-code")= chr "009"
# Expressions ## Replace logicals by integers call_old <- quote(y <- x <- 1 + TRUE) call_new <- rrapply(call_old, classes = "logical", f = as.numeric, how = "replace" ) str(call_new)
#> language y <- x <- 1 + 1
## Update and decompose call object call_ast <- rrapply(call_old, f = function(x) ifelse(is.logical(x), as.numeric(x), x), how = "list" ) str(call_ast)
#> List of 3 #> $ : symbol <- #> $ : symbol y #> $ :List of 3 #> ..$ : symbol <- #> ..$ : symbol x #> ..$ :List of 3 #> .. ..$ : symbol + #> .. ..$ : num 1 #> .. ..$ : num 1
## Prune and decompose expression expr <- expression(y <- x <- 1, f(g(2 * pi))) is_new_name <- function(x) !exists(as.character(x), envir = baseenv()) expr_prune <- rrapply(expr, classes = "name", condition = is_new_name, how = "prune" ) str(expr_prune)
#> List of 2 #> $ :List of 2 #> ..$ : symbol y #> ..$ :List of 1 #> .. ..$ : symbol x #> $ :List of 2 #> ..$ : symbol f #> ..$ :List of 1 #> .. ..$ : symbol g
## Prune and flatten expression expr_flatten <- rrapply(expr, classes = "name", condition = is_new_name, how = "flatten" ) str(expr_flatten)
#> List of 4 #> $ : symbol y #> $ : symbol x #> $ : symbol f #> $ : symbol g
## Prune and melt expression expr_melt <- rrapply(expr, classes = "name", condition = is_new_name, f = as.character, how = "melt" ) expr_melt
#> L1 L2 L3 value #> 1 1 2 <NA> y #> 2 1 3 2 x #> 3 2 1 <NA> f #> 4 2 2 1 g
## Avoid recursing into call objects rrapply( expr, classes = "language", condition = function(x) !any(sapply(x, is.call)), how = "flatten" )
#> [[1]] #> x <- 1 #> #> [[2]] #> 2 * pi #>