Given a nested list, how to create all possible lists from its elements, while preserving the structure of the nested list?
Nested list:
l = list(
a = list(
b = 1:2
),
c = list(
d = list(
e = 3:4,
f = 5:6
)
),
g = 7
)
Desired output: all possible combinations of the elements of l
, while preserving the structure, e.g.:
# One possible output:
list(
a = list(
b = 1
),
c = list(
d = list(
e = 3,
f = 5
)
),
g = 7
)
# Another possible output:
list(
a = list(
b = 1
),
c = list(
d = list(
e = 4,
f = 5
)
),
g = 7
)
My approach so far is to:
- flatten the list (e.g., as discussed in this answer)
expand.grid()
and get a matrix where each row represents a unique combination- parse every row of the resulting matrix and reconstruct the structure from the
names()
using regular expressions
I am looking for a less cumbersome approach because I have no guarantee that the names of the list elements will not change.
The
relist
function fromutils
seems to be designed for this task:It saves the structure of the list (
skeleton
). This means one can now manipulate the data within the nested list and re-assign it into the structure (flesh
). Here with the first row of the expanded matrix.Note that since the structure stays the same, I need to supply the same amount of elements as in the original list. This is why used
rep
to repeat the element twice. One could also fill it withNA
, I guess.For every possible combination iterate through
r
(expanded):Unequal sublist lengths
Here is an approach --extending on Uwe and Ben's answers-- that also works for arbitrary sublist lengths. Instead of calling
expand.grid
ondata.frame(l)
, first flattenl
to a single-level list and then callexpand.grid
on it:Data
I slightly modified the data structure, so that the sublist components
e
andf
are of unequal length.Combining Ben Nutzer's brilliant answer and Joris Chau's brilliant comment, the answer will become a one-liner:
It creates a list of lists with as many elements as rows returned by
expand.grid()
. The result is better visualised by the output ofstr()
:Putting together the great answers from Ben Nutzer and Joris Chau, we have a way to create all possible combinations from a nested list, regardless of whether some sublist components are of unequal length.
Put together as a function:
Note: If a character type exists in the sublist components, then everything will be coerced to a character. For example:
One--slow--way around this is to
relist
within a loop which will maintain the data in a1x1
dataframe. Accessing the dataframe asdf[, 1]
will give a vector of length 1 of the original type as the element in the input list. For example:Updated
list.combine()
:Then the
retain.element.type()
:Example: