This function iout_nest performs an “inside-out” version of what tidyr::nest does. The data table is a collation of all the nested sub-tables, and the main table is linked parent of those.

My question, is there an existing package or idiom in R that already performs this kind of inside-out nesting?

library(dplyr)
library(tidyr)
#' using the nest() idioms, turn the main and sub-tables inside out into 2 tables
#' keyed by "id"
iout_nest <- function(x, ...) {
  nested <- nest(x, ..., .key = "_data_")
  out <- list(data = dplyr::bind_rows(nested[["_data_"]], .id = "id"))
  nested[["_data_"]] <- NULL
  nested[["id"]] <- as.character(seq_len(nrow(nested)))
  out[["main"]] <- nested
  out
}

Standard tidyr nest

The nested iris table.

(d1 <- iris %>% nest(-Species, -Petal.Width))
## # A tibble: 27 × 3
##    Petal.Width    Species              data
##          <dbl>     <fctr>            <list>
## 1          0.2     setosa <tibble [29 × 3]>
## 2          0.4     setosa  <tibble [7 × 3]>
## 3          0.3     setosa  <tibble [7 × 3]>
## 4          0.1     setosa  <tibble [5 × 3]>
## 5          0.5     setosa  <tibble [1 × 3]>
## 6          0.6     setosa  <tibble [1 × 3]>
## 7          1.4 versicolor  <tibble [7 × 3]>
## 8          1.5 versicolor <tibble [10 × 3]>
## 9          1.3 versicolor <tibble [13 × 3]>
## 10         1.6 versicolor  <tibble [3 × 3]>
## # ... with 17 more rows

Inside out

Turn the same nesting inside-out, into two tables.

(d2 <- iris %>% iout_nest(-Species, -Petal.Width))
## $data
## # A tibble: 150 × 4
##       id Sepal.Length Sepal.Width Petal.Length
##    <chr>        <dbl>       <dbl>        <dbl>
## 1      1          5.1         3.5          1.4
## 2      1          4.9         3.0          1.4
## 3      1          4.7         3.2          1.3
## 4      1          4.6         3.1          1.5
## 5      1          5.0         3.6          1.4
## 6      1          5.0         3.4          1.5
## 7      1          4.4         2.9          1.4
## 8      1          5.4         3.7          1.5
## 9      1          4.8         3.4          1.6
## 10     1          5.8         4.0          1.2
## # ... with 140 more rows
## 
## $main
## # A tibble: 27 × 3
##    Petal.Width    Species    id
##          <dbl>     <fctr> <chr>
## 1          0.2     setosa     1
## 2          0.4     setosa     2
## 3          0.3     setosa     3
## 4          0.1     setosa     4
## 5          0.5     setosa     5
## 6          0.6     setosa     6
## 7          1.4 versicolor     7
## 8          1.5 versicolor     8
## 9          1.3 versicolor     9
## 10         1.6 versicolor    10
## # ... with 17 more rows

Recreate original data.frame from split version

## compare with iris after joining back together
all.equal(d2$data %>% inner_join(d2$main) %>% select(-id), iris)
## Joining, by = "id"
## [1] TRUE