Search code examples
rdata.tablepurrrnested-lists

Change nesting structure of a nested list stored in a data.table


Outline

I am trying to find numbers in a list that amount to a given sum. I managed to calculate all combinations of numbers and their sums with a concise syntax. But I do not manage to restructure the resulting nested list into a nested list of different type.

Minimal example

library(data.table)
library(purrr)

# raw data and basic operation
dt <- data.table(
  amount = c(2,5,9)
)[,
  `:=`(
    # nesting combinations into the data.table
    amount.set = map(1:.N,function(x) combn(amount,x)),
    sum = map(1:.N,function(x) colSums(combn(amount,x)))
  )
]

# desired structure of nested list
desired.output <- data.table(
  sum = c(2,5,9,7,11,14,16),
  amount.set = list(c(2),c(5),c(9),c(2,5),c(2,9),c(5,9),c(2,5,9))
)

How can I achieve the structure in desired.output?


Solution

  • Not sure if we need the intermediate calcs, we can do that with:

    data.table( id = 1:3, amount = c(2,5,9)
      )[, .(amount.set = unlist(lapply(1:.N, combn, x = amount, simplify = FALSE),
                                recursive = FALSE))
      ][, sum_ := sapply(amount.set, sum)][]
    #    amount.set  sum_
    #        <list> <num>
    # 1:          2     2
    # 2:          5     5
    # 3:          9     9
    # 4:        2,5     7
    # 5:        2,9    11
    # 6:        5,9    14
    # 7:      2,5,9    16
    

    Notes:

    • lapply is equivalent to map here
    • the first key difference between this and your first attempt is that I'm using simplify=FALSE, which means that each combination (e.g., c(2,5)) is in its own list instead of a matrix (where each column is a combination);
    • next, since we actually have a nested list structure, we need a non-recursive unlist
    • the second key difference between this and yours is that we calculate the sum on the list based on the actual list of combinations, instead of calculating combn(..) twice