1<%@meta language="R-vignette" content="--------------------------------
2%\VignetteIndexEntry{List Environments}
3%\VignetteAuthor{Henrik Bengtsson}
4%\VignetteKeyword{R}
5%\VignetteKeyword{package}
6%\VignetteKeyword{vignette}
7%\VignetteKeyword{listenv}
8%\VignetteEngine{R.rsp::rsp}
9%\VignetteTangle{FALSE}
10--------------------------------------------------------------------"%>
11<%
12R.utils::use("R.utils")
13use("listenv")
14options("withCapture/newline" = FALSE)
15%>
16# <%@meta name="title"%>
17
18## Summary
19
20_List environments_ are environments that have list-like properties.  They are implemented by the [listenv] package.  The main features of a list environment are summarized in the below table:
21
22| Property                                                                     | list environments |  lists | environments |
23|------------------------------------------------------------------------------|:-----------------:|:------:|:------------:|
24| Number of elements, e.g. `length()`                                          |              yes  |   yes  |         yes  |
25| Named elements, e.g. `names()`, `x$a` and `x[["a"]]`                         |              yes  |   yes  |         yes  |
26| Duplicated names                                                             |              yes  |   yes  |              |
27| Element names are optional                                                   |              yes  |   yes  |              |
28| Indexed elements, e.g. `x[[4]]`                                              |              yes  |   yes  |              |
29| Dimensions, e.g. `dim(x)`                                                    |              yes  |   yes  |              |
30| Names of dimensions, e.g. `dimnames(x)`                                      |              yes  |   yes  |              |
31| Indexing by dimensions, e.g. `x[[2, 4]]` and `x[[2, "D"]]`                   |              yes  |   yes  |              |
32| Multi-element subsetting, e.g. `x[c("a", "c")]`, `x[-1]` and `x[2:1, , 3]`   |              yes  |   yes  |              |
33| Multi-element subsetting preserves element names                             |              yes  |        |              |
34| Removing elements by assigning NULL, e.g. `x$c <- NULL` and `x[1:3] <- NULL` |              yes  |   yes  |              |
35| Removing parts of dimensions by assigning NULL, e.g. `x[,2] <- NULL`         |              yes  |        |              |
36| Mutable, e.g. `y <- x; y$a <- 3; identical(y, x)`                            |              yes  |        |         yes  |
37| Compatible* with `assign()`, `delayedAssign()`, `get()` and `exists()`       |              yes  |        |         yes  |
38
39For example,
40```r
41<%=withCapture({
42x <- listenv(a = 1, b = 2, c = "hello")
43x
44
45length(x)
46names(x)
47x$a
48x[[3]] <- toupper(x[[3]])
49x$c
50
51y <- x
52y$d <- y$a + y[["b"]]
53names(y)[2] <- "a"
54y$a
55y
56identical(y, x)
57
58for (ii in seq_along(x)) {
59  cat(sprintf("Element %d (%s): %s\n", ii, sQuote(names(x)[ii]), x[[ii]]))
60}
61
62x[c(1, 3)] <- list(2, "Hello world!")
63
64x
65y <- as.list(x)
66str(y)
67z <- as.listenv(y)
68z
69identical(z, x)
70all.equal(z, x)
71})%>
72```
73
74## Creating list environments
75List environments are created similarly to lists but also similarly to environments.  To create an empty list environment, use
76```r
77<%=withCapture({
78x <- listenv()
79x
80})%>
81```
82This can later can be populated using named assignments,
83```r
84<%=withCapture({
85x$a <- 1
86x
87})%>
88```
89comparable to how both lists and environments work.  Similarly to lists, they can also be populated using indices, e.g.
90```r
91<%=withCapture({
92x[[2]] <- 2
93x$c <- 3
94x
95})%>
96```
97Just as for lists, a list environment is expanded with `NULL` elements whenever a new element is added that is beyond the current length plus one, e.g.
98```r
99<%=withCapture({
100x[[5]] <- 5
101x
102x[[4]]
103})%>
104```
105
106As with lists, the above list environment can also be created from the start, e.g.
107```r
108<%=withCapture({
109x <- listenv(a = 1, 3, c = 4, NULL, 5)
110x
111})%>
112```
113
114
115As for lists, the length of a list environment can at any time be increased or decreased by assigning it a new length.
116If decreased, elements are dropped, e.g.
117```r
118<%=withCapture({
119x
120length(x) <- 2
121x
122x[[1]]
123x[[2]]
124})%>
125```
126If increased, new elements are populated with unnamed elements of `NULL`, e.g.
127```r
128<%=withCapture({
129length(x) <- 4
130x
131x[[3]]
132x[[4]]
133})%>
134```
135
136To allocate an "empty" list environment (with all `NULL`:s) of a given length, do
137```r
138<%=withCapture({
139x <- listenv()
140length(x) <- 4
141x
142})%>
143```
144_Note_: Unfortunately, it is _not_ possible to use `x <- vector("listenv", length = 4)`; that construct is only supported for the basic data types.
145
146Elements can be dropped by assigning `NULL`, e.g. to drop the first and third element of a list environment, do:
147```r
148<%=withCapture({
149x[c(1, 3)] <- NULL
150x
151})%>
152```
153
154
155## Iterating over elements
156
157### Iterating over elements by names
158Analogously to lists and plain environments, it is possible to iterate over elements of list environments by the element names.  For example,
159```r
160<%=withCapture({
161x <- listenv(a = 1, b = 2, c = 3)
162for (name in names(x)) {
163  cat(sprintf("Element %s: %s\n", sQuote(name), x[[name]]))
164}
165})%>
166```
167
168### Iterating over elements by indices
169Analogously to lists, but contrary to plain environments, it is also possible to iterate over elements by their indices.  For example,
170```r
171<%=withCapture({
172x <- listenv(a = 1, b = 2, c = 3)
173for (ii in seq_along(x)) {
174  cat(sprintf("Element %d: %s\n", ii, x[[ii]]))
175}
176})%>
177```
178
179
180## Coercion to and from list environments
181
182### Coercing to lists and vectors
183
184Coercing a list environment to a list:
185```r
186<%=withCapture({
187x <- listenv(a = 2, b = 3, c = "hello")
188x
189y <- as.list(x)
190str(y)
191})%>
192```
193
194Coercing a list to a list environment:
195```r
196<%=withCapture({
197z <- as.listenv(y)
198z
199identical(z, x)
200all.equal(z, x)
201})%>
202```
203
204Unlisting:
205```r
206<%=withCapture({
207unlist(x)
208unlist(x[-3])
209unlist(x[1:2], use.names=FALSE)
210})%>
211```
212
213
214## Multi-dimensional list environments
215
216Analogously to lists, and contrary to plain environments, list environments can have dimensions with corresponding names.  For example,
217```r
218<%=withCapture({
219x <- as.listenv(1:6)
220dim(x) <- c(2, 3)
221dimnames(x) <- list(c("a", "b"), c("A", "B","C"))
222x
223})%>
224```
225An easy way to quickly get an overview is to coerce to a list, e.g.
226```r
227<%=withCapture({
228as.list(x)
229})%>
230```
231Individual elements of a list environment can be accessed using standard subsetting syntax, e.g.
232```r
233<%=withCapture({
234x[["a", "B"]]
235x[[1, 2]]
236x[[1, "B"]]
237})%>
238```
239We can assign individual elements similarly, e.g.
240```r
241<%=withCapture({
242x[["b", "B"]] <- -x[["b", "B"]]
243as.list(x)
244})%>
245```
246We can also assign multiple elements through dimensional subsetting, e.g.
247```r
248<%=withCapture({
249x[2, -1] <- 98:99
250as.list(x)
251x["a", c(1, 3)] <- list(97, "foo")
252as.list(x)
253x[] <- 1:6
254as.list(x)
255})%>
256```
257
258Concurrently with dimensional names it is possible to have names of the individual elements just as for list environments without dimensions.  For example,
259```r
260<%=withCapture({
261names(x) <- letters[seq_along(x)]
262x
263x[["a"]]
264x[["f"]]
265x[c("a", "f")]
266unlist(x)
267as.list(x)
268})%>
269```
270Contrary to lists, element names are preserved also with multi-dimensional subsetting, e.g.
271```r
272<%=withCapture({
273x[1, 2]
274x[1, 2, drop = FALSE]
275x[1:2, 2:1]
276x[2, ]
277x[2, , drop = FALSE]
278x["b", -2, drop = FALSE]
279})%>
280```
281
282
283Note, whenever dimensions are set using `dim(x) <- dims` both the dimensional names and the element names are removed, e.g.
284```r
285> dim(x) <- NULL
286> names(x)
287NULL
288```
289This behavior is by design, cf. `help("dim", package="base")`.
290
291
292To allocate an "empty" list environment array (with all `NULL`:s) of a given dimension, do
293```r
294<%=withCapture({
295x <- listenv()
296dim(x) <- c(2, 3)
297dimnames(x) <- list(c("a", "b"), c("A", "B", "C"))
298x
299})%>
300```
301Rows and columns can be dropped by assigning `NULL`, e.g. to drop the first and third column of a list-environment matrix, do:
302```r
303<%=withCapture({
304x[, c(1, 3)] <- NULL
305x
306})%>
307```
308
309
310<%---
311Because of this, the listenv package provides the `undim()` function, which removes the dimensions but preserves the names, e.g.
312```r
313<%=withCapture({
314x <- undim(x)
315names(x)
316})%>
317```
318_Warning_: Since list environments _and their attributes_ are mutable, calling
319```r
320undim(x)
321```
322will have the same effect as
323```r
324x <- undim(x)
325```
326That is, the dimension attributes of `x` will be changed.  The reason for this is explained in Section 'Important about environments' above.
327---%>
328
329
330## Important about environments
331List environments are as their name suggests _environments_.  Whenever working with environments in R, it is important to understand that _environments are mutable_ whereas all other of the basic data types in R are immutable.  For example, consider the following function that assigns zero to element `a` of object `x`:
332```r
333<%=withCapture({
334setA <- function(x) {
335  x$a <- 0
336  x
337}
338})%>
339```
340If we pass a regular list to this function,
341```r
342<%=withCapture({
343x <- list(a = 1)
344y <- setA(x)
345x$a
346y$a
347})%>
348```
349we see that `x` is unaffected by the assignment.  This is because _lists are immutable_ in R.  However, if we pass an environment instead,
350```r
351<%=withCapture({
352x <- new.env()
353x$a <- 1
354y <- setA(x)
355x$a
356y$a
357})%>
358```
359we find that `x` was affected by the assignment.  This is because _environments are mutable_ in R.  Since list environments inherits from environments, this also goes for them, e.g.
360```r
361<%=withCapture({
362x <- listenv(a = 1)
363y <- setA(x)
364x$a
365y$a
366})%>
367```
368
369What is also important to understand is that it is not just the _content_ of an environment that is mutable but also its _attributes_.  For example,
370```r
371<%=withCapture({
372x <- listenv(a = 1)
373y <- x
374attr(y, "foo") <- "Hello!"
375attr(x, "foo")
376})%>
377```
378More importantly, since dimensions and their names are also attributes, this also means they are mutable.  For example,
379```r
380<%=withCapture({
381x <- as.listenv(1:6)
382dim(x) <- c(2, 3)
383x
384y <- x
385dim(y) <- c(3, 2)
386x
387})%>
388```
389
390
391[listenv]: https://cran.r-project.org/package=listenv
392
393---
394Copyright Henrik Bengtsson, 2015-2018
395