library(listr)
The idea behind the listr
package is to make working
with lists with in R a bit more convenient. There is nothing wrong with
lists in R per se, but sometimes the tools around lists and the syntax
can be a bit confusing and complicated. With the tools provided by
listr
common tasks with lists and especially lists
containing data frames can hopefully be simplified by providing a
consistent and easy to read syntax that is also suited for use with
pipes.
For our examples below, assume we split the mtcars
data
by the cyl
variable.
<- split(mtcars, mtcars$cyl) by_cyl
<- by_cyl |>
by_cyl list_rename("cyl4" = `4`, "cyl6" = `6`, "cyl8" = `8`)
|> list_select(cyl6)
by_cyl #> $cyl6
#> mpg cyl disp hp drat wt qsec vs am gear carb
#> Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
#> Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
#> Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
#> Valiant 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1
#> Merc 280 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4
#> Merc 280C 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4
#> Ferrari Dino 19.7 6 145.0 175 3.62 2.770 15.50 0 1 5 6
There is both list_extract
and list_select
that can appear a bit similar in some cases. However, there are some
important distinctions between both:
list_select
allows you to select several items from a
list.list_select
always returns a list.In contrast
list_extract
only allows you to select a single
item.list_extract
unlists the selected item.Thus, list_select
is equivalent to selecting from a list
with a single square bracket, while list_extract
is
equivalent to using double square brackets.
|> list_select(1, 2)
by_cyl #> $cyl4
#> mpg cyl disp hp drat wt qsec vs am gear carb
#> Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1
#> Merc 240D 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2
#> Merc 230 22.8 4 140.8 95 3.92 3.150 22.90 1 0 4 2
#> Fiat 128 32.4 4 78.7 66 4.08 2.200 19.47 1 1 4 1
#> Honda Civic 30.4 4 75.7 52 4.93 1.615 18.52 1 1 4 2
#> Toyota Corolla 33.9 4 71.1 65 4.22 1.835 19.90 1 1 4 1
#> Toyota Corona 21.5 4 120.1 97 3.70 2.465 20.01 1 0 3 1
#> Fiat X1-9 27.3 4 79.0 66 4.08 1.935 18.90 1 1 4 1
#> Porsche 914-2 26.0 4 120.3 91 4.43 2.140 16.70 0 1 5 2
#> Lotus Europa 30.4 4 95.1 113 3.77 1.513 16.90 1 1 5 2
#> Volvo 142E 21.4 4 121.0 109 4.11 2.780 18.60 1 1 4 2
#>
#> $cyl6
#> mpg cyl disp hp drat wt qsec vs am gear carb
#> Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
#> Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
#> Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
#> Valiant 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1
#> Merc 280 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4
#> Merc 280C 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4
#> Ferrari Dino 19.7 6 145.0 175 3.62 2.770 15.50 0 1 5 6
<- by_cyl |> list_extract(cyl4)
cyl4
cyl4#> mpg cyl disp hp drat wt qsec vs am gear carb
#> Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1
#> Merc 240D 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2
#> Merc 230 22.8 4 140.8 95 3.92 3.150 22.90 1 0 4 2
#> Fiat 128 32.4 4 78.7 66 4.08 2.200 19.47 1 1 4 1
#> Honda Civic 30.4 4 75.7 52 4.93 1.615 18.52 1 1 4 2
#> Toyota Corolla 33.9 4 71.1 65 4.22 1.835 19.90 1 1 4 1
#> Toyota Corona 21.5 4 120.1 97 3.70 2.465 20.01 1 0 3 1
#> Fiat X1-9 27.3 4 79.0 66 4.08 1.935 18.90 1 1 4 1
#> Porsche 914-2 26.0 4 120.3 91 4.43 2.140 16.70 0 1 5 2
#> Lotus Europa 30.4 4 95.1 113 3.77 1.513 16.90 1 1 5 2
#> Volvo 142E 21.4 4 121.0 109 4.11 2.780 18.60 1 1 4 2
The list_remove
function is straightforward.
<- by_cyl |> list_remove(cyl4)
by_cyl
by_cyl#> $cyl6
#> mpg cyl disp hp drat wt qsec vs am gear carb
#> Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
#> Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
#> Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
#> Valiant 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1
#> Merc 280 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4
#> Merc 280C 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4
#> Ferrari Dino 19.7 6 145.0 175 3.62 2.770 15.50 0 1 5 6
#>
#> $cyl8
#> mpg cyl disp hp drat wt qsec vs am gear carb
#> Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2
#> Duster 360 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4
#> Merc 450SE 16.4 8 275.8 180 3.07 4.070 17.40 0 0 3 3
#> Merc 450SL 17.3 8 275.8 180 3.07 3.730 17.60 0 0 3 3
#> Merc 450SLC 15.2 8 275.8 180 3.07 3.780 18.00 0 0 3 3
#> Cadillac Fleetwood 10.4 8 472.0 205 2.93 5.250 17.98 0 0 3 4
#> Lincoln Continental 10.4 8 460.0 215 3.00 5.424 17.82 0 0 3 4
#> Chrysler Imperial 14.7 8 440.0 230 3.23 5.345 17.42 0 0 3 4
#> Dodge Challenger 15.5 8 318.0 150 2.76 3.520 16.87 0 0 3 2
#> AMC Javelin 15.2 8 304.0 150 3.15 3.435 17.30 0 0 3 2
#> Camaro Z28 13.3 8 350.0 245 3.73 3.840 15.41 0 0 3 4
#> Pontiac Firebird 19.2 8 400.0 175 3.08 3.845 17.05 0 0 3 2
#> Ford Pantera L 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4
#> Maserati Bora 15.0 8 301.0 335 3.54 3.570 14.60 0 1 5 8
The opposite can be achieved with list_insert
and its
more specialised versions list_append
and
list_prepend
.
<- by_cyl |> list_prepend(cyl4, name = "cyl4")
by_cyl
by_cyl#> $cyl4
#> mpg cyl disp hp drat wt qsec vs am gear carb
#> Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1
#> Merc 240D 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2
#> Merc 230 22.8 4 140.8 95 3.92 3.150 22.90 1 0 4 2
#> Fiat 128 32.4 4 78.7 66 4.08 2.200 19.47 1 1 4 1
#> Honda Civic 30.4 4 75.7 52 4.93 1.615 18.52 1 1 4 2
#> Toyota Corolla 33.9 4 71.1 65 4.22 1.835 19.90 1 1 4 1
#> Toyota Corona 21.5 4 120.1 97 3.70 2.465 20.01 1 0 3 1
#> Fiat X1-9 27.3 4 79.0 66 4.08 1.935 18.90 1 1 4 1
#> Porsche 914-2 26.0 4 120.3 91 4.43 2.140 16.70 0 1 5 2
#> Lotus Europa 30.4 4 95.1 113 3.77 1.513 16.90 1 1 5 2
#> Volvo 142E 21.4 4 121.0 109 4.11 2.780 18.60 1 1 4 2
#>
#> $cyl6
#> mpg cyl disp hp drat wt qsec vs am gear carb
#> Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
#> Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
#> Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
#> Valiant 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1
#> Merc 280 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4
#> Merc 280C 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4
#> Ferrari Dino 19.7 6 145.0 175 3.62 2.770 15.50 0 1 5 6
#>
#> $cyl8
#> mpg cyl disp hp drat wt qsec vs am gear carb
#> Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2
#> Duster 360 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4
#> Merc 450SE 16.4 8 275.8 180 3.07 4.070 17.40 0 0 3 3
#> Merc 450SL 17.3 8 275.8 180 3.07 3.730 17.60 0 0 3 3
#> Merc 450SLC 15.2 8 275.8 180 3.07 3.780 18.00 0 0 3 3
#> Cadillac Fleetwood 10.4 8 472.0 205 2.93 5.250 17.98 0 0 3 4
#> Lincoln Continental 10.4 8 460.0 215 3.00 5.424 17.82 0 0 3 4
#> Chrysler Imperial 14.7 8 440.0 230 3.23 5.345 17.42 0 0 3 4
#> Dodge Challenger 15.5 8 318.0 150 2.76 3.520 16.87 0 0 3 2
#> AMC Javelin 15.2 8 304.0 150 3.15 3.435 17.30 0 0 3 2
#> Camaro Z28 13.3 8 350.0 245 3.73 3.840 15.41 0 0 3 4
#> Pontiac Firebird 19.2 8 400.0 175 3.08 3.845 17.05 0 0 3 2
#> Ford Pantera L 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4
#> Maserati Bora 15.0 8 301.0 335 3.54 3.570 14.60 0 1 5 8
There is a certain focus on operations with data frames in this package.
The function list_name_to_df
adds a column to each data
frame in the list containing the name of the list item. This is
particularly useful if you have a list where each item is data from an
experimental group or something similar.
|>
by_cyl list_name_to_df() |>
list_select(1)
#> $cyl4
#> mpg cyl disp hp drat wt qsec vs am gear carb .group
#> Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1 cyl4
#> Merc 240D 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2 cyl4
#> Merc 230 22.8 4 140.8 95 3.92 3.150 22.90 1 0 4 2 cyl4
#> Fiat 128 32.4 4 78.7 66 4.08 2.200 19.47 1 1 4 1 cyl4
#> Honda Civic 30.4 4 75.7 52 4.93 1.615 18.52 1 1 4 2 cyl4
#> Toyota Corolla 33.9 4 71.1 65 4.22 1.835 19.90 1 1 4 1 cyl4
#> Toyota Corona 21.5 4 120.1 97 3.70 2.465 20.01 1 0 3 1 cyl4
#> Fiat X1-9 27.3 4 79.0 66 4.08 1.935 18.90 1 1 4 1 cyl4
#> Porsche 914-2 26.0 4 120.3 91 4.43 2.140 16.70 0 1 5 2 cyl4
#> Lotus Europa 30.4 4 95.1 113 3.77 1.513 16.90 1 1 5 2 cyl4
#> Volvo 142E 21.4 4 121.0 109 4.11 2.780 18.60 1 1 4 2 cyl4
Using list_bind
you can bind together data frame
elements of a list. This is roughly similar to calling
do.call(rbind, list)
or the same with cbind
,
but there is a bit more flexibility.
|>
by_cyl list_bind(cyl4, cyl6, what = "rows", name = "cyl4_and_6")
#> $cyl4_and_6
#> mpg cyl disp hp drat wt qsec vs am gear carb
#> cyl4.Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1
#> cyl4.Merc 240D 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2
#> cyl4.Merc 230 22.8 4 140.8 95 3.92 3.150 22.90 1 0 4 2
#> cyl4.Fiat 128 32.4 4 78.7 66 4.08 2.200 19.47 1 1 4 1
#> cyl4.Honda Civic 30.4 4 75.7 52 4.93 1.615 18.52 1 1 4 2
#> cyl4.Toyota Corolla 33.9 4 71.1 65 4.22 1.835 19.90 1 1 4 1
#> cyl4.Toyota Corona 21.5 4 120.1 97 3.70 2.465 20.01 1 0 3 1
#> cyl4.Fiat X1-9 27.3 4 79.0 66 4.08 1.935 18.90 1 1 4 1
#> cyl4.Porsche 914-2 26.0 4 120.3 91 4.43 2.140 16.70 0 1 5 2
#> cyl4.Lotus Europa 30.4 4 95.1 113 3.77 1.513 16.90 1 1 5 2
#> cyl4.Volvo 142E 21.4 4 121.0 109 4.11 2.780 18.60 1 1 4 2
#> cyl6.Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
#> cyl6.Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
#> cyl6.Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
#> cyl6.Valiant 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1
#> cyl6.Merc 280 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4
#> cyl6.Merc 280C 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4
#> cyl6.Ferrari Dino 19.7 6 145.0 175 3.62 2.770 15.50 0 1 5 6
#>
#> $cyl8
#> mpg cyl disp hp drat wt qsec vs am gear carb
#> Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2
#> Duster 360 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4
#> Merc 450SE 16.4 8 275.8 180 3.07 4.070 17.40 0 0 3 3
#> Merc 450SL 17.3 8 275.8 180 3.07 3.730 17.60 0 0 3 3
#> Merc 450SLC 15.2 8 275.8 180 3.07 3.780 18.00 0 0 3 3
#> Cadillac Fleetwood 10.4 8 472.0 205 2.93 5.250 17.98 0 0 3 4
#> Lincoln Continental 10.4 8 460.0 215 3.00 5.424 17.82 0 0 3 4
#> Chrysler Imperial 14.7 8 440.0 230 3.23 5.345 17.42 0 0 3 4
#> Dodge Challenger 15.5 8 318.0 150 2.76 3.520 16.87 0 0 3 2
#> AMC Javelin 15.2 8 304.0 150 3.15 3.435 17.30 0 0 3 2
#> Camaro Z28 13.3 8 350.0 245 3.73 3.840 15.41 0 0 3 4
#> Pontiac Firebird 19.2 8 400.0 175 3.08 3.845 17.05 0 0 3 2
#> Ford Pantera L 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4
#> Maserati Bora 15.0 8 301.0 335 3.54 3.570 14.60 0 1 5 8
As the list_bind
function wraps calls to
rbind
and cbind
it will have the same effect
on names as calling those two functions directly.
Finally, there is also list_join_df
allowing to form a
single element out of many by joining data on an index.
Finally, there is list_flatten
which takes in a list
with nested list and flattens it. The depth of the flattening process
can be specified, by default all items are moved to one level.
<- list(
foo 1,
list(1, 2, 3,
list(4, 5, 6),
list(7, 8, 9,
list(10, 11,
list(12))),
13, 14),
15
)
|> list_flatten()
foo #> $X1
#> [1] 1
#>
#> $X2_1
#> [1] 1
#>
#> $X2_2
#> [1] 2
#>
#> $X2_3
#> [1] 3
#>
#> $X2_4_1
#> [1] 4
#>
#> $X2_4_2
#> [1] 5
#>
#> $X2_4_3
#> [1] 6
#>
#> $X2_5_1
#> [1] 7
#>
#> $X2_5_2
#> [1] 8
#>
#> $X2_5_3
#> [1] 9
#>
#> $X2_5_4_1
#> [1] 10
#>
#> $X2_5_4_2
#> [1] 11
#>
#> $X2_5_4_3_1
#> [1] 12
#>
#> $X2_6
#> [1] 13
#>
#> $X2_7
#> [1] 14
#>
#> $X3
#> [1] 15
|> list_flatten(max_depth = 1)
foo #> $X1
#> [1] 1
#>
#> $X2_1
#> [1] 1
#>
#> $X2_2
#> [1] 2
#>
#> $X2_3
#> [1] 3
#>
#> $X2_4
#> $X2_4[[1]]
#> [1] 4
#>
#> $X2_4[[2]]
#> [1] 5
#>
#> $X2_4[[3]]
#> [1] 6
#>
#>
#> $X2_5
#> $X2_5[[1]]
#> [1] 7
#>
#> $X2_5[[2]]
#> [1] 8
#>
#> $X2_5[[3]]
#> [1] 9
#>
#> $X2_5[[4]]
#> $X2_5[[4]][[1]]
#> [1] 10
#>
#> $X2_5[[4]][[2]]
#> [1] 11
#>
#> $X2_5[[4]][[3]]
#> $X2_5[[4]][[3]][[1]]
#> [1] 12
#>
#>
#>
#>
#> $X2_6
#> [1] 13
#>
#> $X2_7
#> [1] 14
#>
#> $X3
#> [1] 15