The sb2_rec()
and sb2_recin()
methods
are essentially convenient wrappers around [[
and [[<-
,
respectively.
Unlike [[
and [[<-
, these are actually S3 methods,
so package authors can create additional method dispatches. sb2_rec()
will access recursive subsets of lists. sb2_recin()
can do the following things:
replace or transform recursive subsets of a list, using R's default Copy-On-Modify semantics, by specifying the
rp
ortf
argument, respectively.delete a recursive subset of a list, using R's default Copy-On-Modify semantics, by specifying argument
rp = NULL
.extending a list with additional recursive elements, using R's default Copy-On-Modify semantics.
This is done by specifying an out-of-bounds index in argumentrec
, and entering the new values in argumentrp
.
Note that adding surface level elements of a dimensional list will delete the dimension attributes of that list.
Usage
sb2_rec(x, ...)
# Default S3 method
sb2_rec(x, rec, ...)
sb2_recin(x, ...)
# Default S3 method
sb2_recin(x, rec, ..., rp, tf)
Arguments
- x
a list, or list-like object.
- ...
- rec
a strictly positive integer vector or character vector, of length
p
, such thatsb2_rec(x, rec)
is equivalent tox[[ rec[1] ]]...[[ rec[p] ]]
, providing all but the final indexing results in a list.
When on a certain subset level of a nested list, multiple subsets with the same name exist, only the first one will be selected when performing recursive indexing by name, since recursive indexing can only select a single element.NA, NaN, Inf, -Inf
are not valid values forrec
.- rp
optional, and allows for multiple functionalities:
In the simplest case, performs
x[[rec]] <- rp
, using R's default semantics.
Since this is a replacement of a recursive subset,rp
does not necessarily have to be a list itself;rp
can be any type of object.Specifying
rp = NULL
will delete (recursive) subsetsb(x, rec)
.
To specify actualNULL
instead of deleting a subset, userp = list(NULL)
.When
rec
is an integer, and specifies an out-of-bounds subset,sb2_recin()
will add valuerp
to the list.
Any empty positions in between will be filled withNA
.When
rec
is character, and specifies a non-existing name,sb2_recin()
will add valuerp
to the list as a new element at the end.
- tf
an optional function. If specified, performs
x[[rec]] <- tf(x[[rec]])
, using R's default Copy-On-Modify semantics.
Does not support extending a list like argumentrp
.
Value
For sb2_rec()
:
Returns the recursive subset.
For sb2_recin(..., rp = rp)
:
Returns VOID,
but replaces, adds, or deletes the specified recursive subset,
using R's default Copy-On-Modify semantics.
For sb2_recin(..., tf = tf)
:
Returns VOID,
but transforms the specified recursive subset,
using R's default Copy-On-Modify semantics.
Details
Since recursive objects are references to other objects,
extending a list or deleting an element of a list does not copy the entire list,
in contrast to atomic vectors.
Examples
lst <- list(
A = list(
A = list(A = "AAA", B = "AAB"),
A = list(A = "AA2A", B = "AA2B"),
B = list(A = "ABA", B = "ABB")
),
B = list(
A = list(A = "BAA", B = "BAB"),
B = list(A = "BBA", B = "BBB")
),
C = list(
A = 1:10,
B = 11:20
)
)
#############################################################################
# access recursive subsets ====
sb2_rec(lst, c(1,2,2)) # this gives "AA2B"
#> [1] "AA2B"
sb2_rec(lst, c("A", "B", "B")) # this gives "ABB"
#> [1] "ABB"
sb2_rec(lst, c(2,2,1)) # this gives "BBA"
#> [1] "BBA"
sb2_rec(lst, c("B", "B", "A")) # this gives "BBA"
#> [1] "BBA"
#############################################################################
# replace recursive subset with R's default in-place semantics ====
# replace "AAB" using R's default in-place semantics:
sb2_recin(
lst, c("A", "A", "B"),
rp = "THIS IS REPLACED WITH IN-PLACE SEMANTICS"
)
print(lst)
#> $A
#> $A$A
#> $A$A$A
#> [1] "AAA"
#>
#> $A$A$B
#> [1] "THIS IS REPLACED WITH IN-PLACE SEMANTICS"
#>
#>
#> $A$A
#> $A$A$A
#> [1] "AA2A"
#>
#> $A$A$B
#> [1] "AA2B"
#>
#>
#> $A$B
#> $A$B$A
#> [1] "ABA"
#>
#> $A$B$B
#> [1] "ABB"
#>
#>
#>
#> $B
#> $B$A
#> $B$A$A
#> [1] "BAA"
#>
#> $B$A$B
#> [1] "BAB"
#>
#>
#> $B$B
#> $B$B$A
#> [1] "BBA"
#>
#> $B$B$B
#> [1] "BBB"
#>
#>
#>
#> $C
#> $C$A
#> [1] 1 2 3 4 5 6 7 8 9 10
#>
#> $C$B
#> [1] 11 12 13 14 15 16 17 18 19 20
#>
#>
#############################################################################
# transform recursive subsets with R's default in-place semantics ====
sb2_recin(lst, c("C", "A"), tf = \(x)x^2) # transforms lst$C$A
print(lst)
#> $A
#> $A$A
#> $A$A$A
#> [1] "AAA"
#>
#> $A$A$B
#> [1] "THIS IS REPLACED WITH IN-PLACE SEMANTICS"
#>
#>
#> $A$A
#> $A$A$A
#> [1] "AA2A"
#>
#> $A$A$B
#> [1] "AA2B"
#>
#>
#> $A$B
#> $A$B$A
#> [1] "ABA"
#>
#> $A$B$B
#> [1] "ABB"
#>
#>
#>
#> $B
#> $B$A
#> $B$A$A
#> [1] "BAA"
#>
#> $B$A$B
#> [1] "BAB"
#>
#>
#> $B$B
#> $B$B$A
#> [1] "BBA"
#>
#> $B$B$B
#> [1] "BBB"
#>
#>
#>
#> $C
#> $C$A
#> [1] 1 4 9 16 25 36 49 64 81 100
#>
#> $C$B
#> [1] 11 12 13 14 15 16 17 18 19 20
#>
#>
#############################################################################
# add/remove new recursive subsets with R's default in-place semantics ====
sb2_recin(lst, c("C", "D"), rp = "NEW VALUE") # adds lst$C$D
print(lst)
#> $A
#> $A$A
#> $A$A$A
#> [1] "AAA"
#>
#> $A$A$B
#> [1] "THIS IS REPLACED WITH IN-PLACE SEMANTICS"
#>
#>
#> $A$A
#> $A$A$A
#> [1] "AA2A"
#>
#> $A$A$B
#> [1] "AA2B"
#>
#>
#> $A$B
#> $A$B$A
#> [1] "ABA"
#>
#> $A$B$B
#> [1] "ABB"
#>
#>
#>
#> $B
#> $B$A
#> $B$A$A
#> [1] "BAA"
#>
#> $B$A$B
#> [1] "BAB"
#>
#>
#> $B$B
#> $B$B$A
#> [1] "BBA"
#>
#> $B$B$B
#> [1] "BBB"
#>
#>
#>
#> $C
#> $C$A
#> [1] 1 4 9 16 25 36 49 64 81 100
#>
#> $C$B
#> [1] 11 12 13 14 15 16 17 18 19 20
#>
#> $C$D
#> [1] "NEW VALUE"
#>
#>
sb2_recin(lst, c("C", "A"), rp = NULL) # removes lst$C$A
print(lst) # notice lst$C$A is GONE
#> $A
#> $A$A
#> $A$A$A
#> [1] "AAA"
#>
#> $A$A$B
#> [1] "THIS IS REPLACED WITH IN-PLACE SEMANTICS"
#>
#>
#> $A$A
#> $A$A$A
#> [1] "AA2A"
#>
#> $A$A$B
#> [1] "AA2B"
#>
#>
#> $A$B
#> $A$B$A
#> [1] "ABA"
#>
#> $A$B$B
#> [1] "ABB"
#>
#>
#>
#> $B
#> $B$A
#> $B$A$A
#> [1] "BAA"
#>
#> $B$A$B
#> [1] "BAB"
#>
#>
#> $B$B
#> $B$B$A
#> [1] "BBA"
#>
#> $B$B$B
#> [1] "BBB"
#>
#>
#>
#> $C
#> $C$B
#> [1] 11 12 13 14 15 16 17 18 19 20
#>
#> $C$D
#> [1] "NEW VALUE"
#>
#>
#############################################################################
# Modify View of List By Reference ====
x <- list(
a = data.table::data.table(cola = 1:10, colb = letters[1:10]),
b = data.table::data.table(cola = 11:20, colb = letters[11:20])
)
print(x)
#> $a
#> cola colb
#> <int> <char>
#> 1: 1 a
#> 2: 2 b
#> 3: 3 c
#> 4: 4 d
#> 5: 5 e
#> 6: 6 f
#> 7: 7 g
#> 8: 8 h
#> 9: 9 i
#> 10: 10 j
#>
#> $b
#> cola colb
#> <int> <char>
#> 1: 11 k
#> 2: 12 l
#> 3: 13 m
#> 4: 14 n
#> 5: 15 o
#> 6: 16 p
#> 7: 17 q
#> 8: 18 r
#> 9: 19 s
#> 10: 20 t
#>
myref <- sb2_rec(x, "a")
address(myref) == address(x$a) # they are the same
#> [1] TRUE
sb2_set(myref, vars = "cola", tf = \(x)x^2)
print(x) # notice x has been changed
#> $a
#> cola colb
#> <num> <char>
#> 1: 1 a
#> 2: 4 b
#> 3: 9 c
#> 4: 16 d
#> 5: 25 e
#> 6: 36 f
#> 7: 49 g
#> 8: 64 h
#> 9: 81 i
#> 10: 100 j
#>
#> $b
#> cola colb
#> <int> <char>
#> 1: 11 k
#> 2: 12 l
#> 3: 13 m
#> 4: 14 n
#> 5: 15 o
#> 6: 16 p
#> 7: 17 q
#> 8: 18 r
#> 9: 19 s
#> 10: 20 t
#>