How to create permutation of named tuple values

You could use

ntpermutations(nt_in) = [NamedTuple{keys(nt_in)}(reverse(t)) for t in Iterators.product(reverse(nt_in)...)] |> vec
julia> nt_in = (; category = [1, 3, 4], letter = ["a", "b", "c"], score = [1.1, 4.0], thing = ["hat", "cat"])
(category = [1, 3, 4], letter = ["a", "b", "c"], score = [1.1, 4.0], thing = ["hat", "cat"])

julia> nt = ntpermutations(nt_in)
36-element Vector{@NamedTuple{category::Int64, letter::String, score::Float64, thing::String}}:
 (category = 1, letter = "a", score = 1.1, thing = "hat")
 (category = 1, letter = "a", score = 1.1, thing = "cat")
 (category = 1, letter = "a", score = 4.0, thing = "hat")
 (category = 1, letter = "a", score = 4.0, thing = "cat")
 (category = 1, letter = "b", score = 1.1, thing = "hat")
 (category = 1, letter = "b", score = 1.1, thing = "cat")
 (category = 1, letter = "b", score = 4.0, thing = "hat")
 (category = 1, letter = "b", score = 4.0, thing = "cat")
 (category = 1, letter = "c", score = 1.1, thing = "hat")
 (category = 1, letter = "c", score = 1.1, thing = "cat")
 (category = 1, letter = "c", score = 4.0, thing = "hat")
 (category = 1, letter = "c", score = 4.0, thing = "cat")
 (category = 3, letter = "a", score = 1.1, thing = "hat")
 ⋮
 (category = 4, letter = "a", score = 1.1, thing = "hat")
 (category = 4, letter = "a", score = 1.1, thing = "cat")
 (category = 4, letter = "a", score = 4.0, thing = "hat")
 (category = 4, letter = "a", score = 4.0, thing = "cat")
 (category = 4, letter = "b", score = 1.1, thing = "hat")
 (category = 4, letter = "b", score = 1.1, thing = "cat")
 (category = 4, letter = "b", score = 4.0, thing = "hat")
 (category = 4, letter = "b", score = 4.0, thing = "cat")
 (category = 4, letter = "c", score = 1.1, thing = "hat")
 (category = 4, letter = "c", score = 1.1, thing = "cat")
 (category = 4, letter = "c", score = 4.0, thing = "hat")
 (category = 4, letter = "c", score = 4.0, thing = "cat")

If you don’t care about the order, you can remove the reverses.

Explanation

  • Iterators.product(reverse(nt_in)...) creates an iterator containing all possible tuples whose entries are taken from the elements in the fields of nt_in. The first axis in Iterators.product will cycle the fastest. Thanks to the reverse, nt_in’s first field (category) is put at the back and hence changes slowest.
  • NamedTuple{keys(nt_in)}(reverse(t)) takes such a tuple t and converts it in a NamedTuple with the same names as nt_in. We have to undo the reverse from before.
  • |> vec: Iterators.product produces an n-dimensional structure, where n = length(nt_in). The list comprehension then creates an Array{@NamedTuple{...}, n}, which we flatten to a Vector.
1 Like