rlist provides miscellaneous functions to assist data manipulation. These functions are mainly designed to alter the structure of an list object.

`list.append()`

appends an element to a list and `list.prepend()`

prepends an element to a list.

```
library(rlist)
list.append(list(a=1, b=1), c=1)
```

```
# $a
# [1] 1
#
# $b
# [1] 1
#
# $c
# [1] 1
```

```
list.prepend(list(b=1, c=2), a=0)
```

```
# $a
# [1] 0
#
# $b
# [1] 1
#
# $c
# [1] 2
```

The function also works with vector.

```
list.append(1:3, 4)
```

```
# [1] 1 2 3 4
```

```
list.prepend(1:3, 0)
```

```
# [1] 0 1 2 3
```

The names of the vector can be well handled.

```
list.append(c(a=1,b=2), c=3)
```

```
# a b c
# 1 2 3
```

```
list.prepend(c(b=2,c=3), a=1)
```

```
# a b c
# 1 2 3
```

`list.reverse()`

simply reverses a list or vector.

```
list.reverse(1:10)
```

```
# [1] 10 9 8 7 6 5 4 3 2 1
```

`list.zip()`

combines multiple lists element-wisely. In other words, the function takes the first element from all parameters, and then the second, and so on.

```
str(list.zip(a=c(1,2,3), b=c(4,5,6)))
```

```
# List of 3
# $ :List of 2
# ..$ a: num 1
# ..$ b: num 4
# $ :List of 2
# ..$ a: num 2
# ..$ b: num 5
# $ :List of 2
# ..$ a: num 3
# ..$ b: num 6
```

The list elements need not be atomic vectors. They can be any lists.

```
str(list.zip(x=list(1,"x"), y=list("y",2)))
```

```
# List of 2
# $ :List of 2
# ..$ x: num 1
# ..$ y: chr "y"
# $ :List of 2
# ..$ x: chr "x"
# ..$ y: num 2
```

The parameters do not have to be the same type.

```
str(list.zip(x=c(1,2), y=list("x","y")))
```

```
# List of 2
# $ :List of 2
# ..$ x: num 1
# ..$ y: chr "x"
# $ :List of 2
# ..$ x: num 2
# ..$ y: chr "y"
```

`list.rbind()`

binds atomic vectors by row and `list.cbind()`

by column.

```
scores <- list(score1=c(10,9,10),score2=c(8,9,6),score3=c(9,8,10))
list.rbind(scores)
```

```
# [,1] [,2] [,3]
# score1 10 9 10
# score2 8 9 6
# score3 9 8 10
```

```
list.cbind(scores)
```

```
# score1 score2 score3
# [1,] 10 8 9
# [2,] 9 9 8
# [3,] 10 6 10
```

Note that the two functions finally call `rbind()`

and `cbind()`

, respectively, which result in matrix or data frame.

If a list of lists are supplied, then a matrix of `list`

will be created.

```
scores2 <- list(score1=list(10,9,10),
score2=list(8,9,6),type=list("a","b","a"))
rscores2 <- list.rbind(scores2)
rscores2
```

```
# [,1] [,2] [,3]
# score1 10 9 10
# score2 8 9 6
# type "a" "b" "a"
```

`rscores2`

is a matrix of *lists* rather than atomic values.

```
rscores2[1,1]
```

```
# $score1
# [1] 10
```

```
rscores2[,1]
```

```
# $score1
# [1] 10
#
# $score2
# [1] 8
#
# $type
# [1] "a"
```

This is not a common practice and may lead to unexpected mistakes if one is not fully aware of it and take for granted that the extracted value should be an atomic value like a number or string. Therefore, it is not recommended to either `list.rbind()`

or `list.cbind()`

a list of lists.

To create a `data.frame`

from a list of lists, use `list.stack()`

. It is particularly useful when we want to transform a non-tabular data to a stage where it actually fits a tabular form.

For example, a list of lists with the same single-entry fields can be transformed to a equivalent data frame.

```
nontab <- list(list(type="A",score=10),list(type="B",score=9))
list.stack(nontab)
```

```
# type score
# 1 A 10
# 2 B 9
```

For non-tabular data, we can select fields or columns in the data and *stack* the records together to create a data frame.

```
library(pipeR)
list.load("https://renkun-ken.github.io/rlist-tutorial/data/sample.json") %>>%
list.select(Name, Age) %>>%
list.stack
```

```
# Name Age
# 1 Ken 24
# 2 James 25
# 3 Penny 24
```

`list`

is powerful in its recursive nature. Sometimes, however, we don't need its recursive feature but want to *flatten* it so that all its child elements are put to the first level.

`list.flatten()`

recursively extract all elements at all levels and put them to the first level.

```
data <- list(list(a=1,b=2),list(c=1,d=list(x=1,y=2)))
str(data)
```

```
# List of 2
# $ :List of 2
# ..$ a: num 1
# ..$ b: num 2
# $ :List of 2
# ..$ c: num 1
# ..$ d:List of 2
# .. ..$ x: num 1
# .. ..$ y: num 2
```

```
list.flatten(data)
```

```
# $a
# [1] 1
#
# $b
# [1] 2
#
# $c
# [1] 1
#
# $d.x
# [1] 1
#
# $d.y
# [1] 2
```

`list.names()`

can be used to set names of list elements by expression.

```
people <- list.load("https://renkun-ken.github.io/rlist-tutorial/data/sample.json") %>>%
list.select(Name, Age)
str(people)
```

```
# List of 3
# $ :List of 2
# ..$ Name: chr "Ken"
# ..$ Age : int 24
# $ :List of 2
# ..$ Name: chr "James"
# ..$ Age : int 25
# $ :List of 2
# ..$ Name: chr "Penny"
# ..$ Age : int 24
```

Note that the elements in `people`

currently do not have names. In some cases, it would be nice to assign appropriate names to those elements so that the distinctive information can be preserved in list transformations.

```
npeople <- people %>>%
list.names(Name)
str(npeople)
```

```
# List of 3
# $ Ken :List of 2
# ..$ Name: chr "Ken"
# ..$ Age : int 24
# $ James:List of 2
# ..$ Name: chr "James"
# ..$ Age : int 25
# $ Penny:List of 2
# ..$ Name: chr "Penny"
# ..$ Age : int 24
```

The names of the list elements can be preserved in various types of data manipulation. For example,

```
npeople %>>%
list.mapv(Age)
```

```
# Ken James Penny
# 24 25 24
```

The names of the resulted vector exactly come from the names of the list elements.

Sometimes it is useful to take a sample from a list. If it is a weighted sampling, the weights are in most cases related with individual subjects. `list.sample()`

is a wrapper function of the built-in `sample()`

but provides `weight`

argument as an expression to evaluate for each list element to determine the weight of that element.

The following example shows a simple sampling from integers 1-10 by weight of squares.

```
set.seed(0)
list.sample(1:10, size = 3, weight = .^2)
```

```
# [1] 5 10 8
```