3

Permutations of a Set of Elements

I have a Julia snippet which generates all possible 4-tuples with 3 possible elements in each slot:

julia> collect(Iterators.product(ntuple(_ -> 1:3, 4)...))
3×3×3×3 Array{NTuple{4, Int64}, 4}:
[:, :, 1, 1] =
 (1, 1, 1, 1)  (1, 2, 1, 1)  (1, 3, 1, 1)
 (2, 1, 1, 1)  (2, 2, 1, 1)  (2, 3, 1, 1)
 (3, 1, 1, 1)  (3, 2, 1, 1)  (3, 3, 1, 1)

[:, :, 2, 1] =
 (1, 1, 2, 1)  (1, 2, 2, 1)  (1, 3, 2, 1)
 (2, 1, 2, 1)  (2, 2, 2, 1)  (2, 3, 2, 1)
 (3, 1, 2, 1)  (3, 2, 2, 1)  (3, 3, 2, 1)

[:, :, 3, 1] =
 (1, 1, 3, 1)  (1, 2, 3, 1)  (1, 3, 3, 1)
 (2, 1, 3, 1)  (2, 2, 3, 1)  (2, 3, 3, 1)
 (3, 1, 3, 1)  (3, 2, 3, 1)  (3, 3, 3, 1)

[:, :, 1, 2] =
 (1, 1, 1, 2)  (1, 2, 1, 2)  (1, 3, 1, 2)
 (2, 1, 1, 2)  (2, 2, 1, 2)  (2, 3, 1, 2)
 (3, 1, 1, 2)  (3, 2, 1, 2)  (3, 3, 1, 2)
...

Question

How do I modify this code so that instead of using a range 1:3 for the elements, I select elements out of an array, say [1,5], or a set Set([1,5]), with only 2 possibilities?

kfmfe04
  • 14,936
  • 14
  • 74
  • 140

1 Answers1

2

I think this is what you're looking for:

julia> original = collect(Iterators.product(ntuple(_ -> [1,5], 4)...))
2×2×2×2 Array{NTuple{4, Int64}, 4}:
[:, :, 1, 1] =
 (1, 1, 1, 1)  (1, 5, 1, 1)
 (5, 1, 1, 1)  (5, 5, 1, 1)

[:, :, 2, 1] =
 (1, 1, 5, 1)  (1, 5, 5, 1)
 (5, 1, 5, 1)  (5, 5, 5, 1)

[:, :, 1, 2] =
 (1, 1, 1, 5)  (1, 5, 1, 5)
 (5, 1, 1, 5)  (5, 5, 1, 5)

[:, :, 2, 2] =
 (1, 1, 5, 5)  (1, 5, 5, 5)
 (5, 1, 5, 5)  (5, 5, 5, 5)

julia> flattened = [original...]
16-element Vector{NTuple{4, Int64}}:
 (1, 1, 1, 1)
 (5, 1, 1, 1)
 (1, 5, 1, 1)
 (5, 5, 1, 1)
 (1, 1, 5, 1)
 (5, 1, 5, 1)
 (1, 5, 5, 1)
 (5, 5, 5, 1)
 (1, 1, 1, 5)
 (5, 1, 1, 5)
 (1, 5, 1, 5)
 (5, 5, 1, 5)
 (1, 1, 5, 5)
 (5, 1, 5, 5)
 (1, 5, 5, 5)
 (5, 5, 5, 5)

So, it's possible to simply substitute an array or set for the iterator. Afterwards, you can flatten the resulting matrix with the splat operator.

Additionally, here is how elements can be accessed in the form A[i,j] using list comprehension:

julia> original  =  collect(Iterators.product(ntuple(_ -> 1:3, 4)...));
julia> newMatrix = [original[:,:,a,b] for a in 1:3, b in 1:3];

julia> newMatrix[2,3]
3×3 Matrix{NTuple{4, Int64}}:
 (1, 1, 2, 3)  (1, 2, 2, 3)  (1, 3, 2, 3)
 (2, 1, 2, 3)  (2, 2, 2, 3)  (2, 3, 2, 3)
 (3, 1, 2, 3)  (3, 2, 2, 3)  (3, 3, 2, 3)

julia> typeof(newMatrix)
Matrix{Matrix{NTuple{4, Int64}}} (alias for Array{Array{NTuple{4, Int64}, 2}, 2})
Ashlin Harris
  • 414
  • 2
  • 6
  • 1
    Total modification of the code is fine, but would like it to keep it a one liner. Also, maybe I wasn't clear enough - in place of permuting 3 elements `1:3`, I'm looking to permute two elements `[1,5]`. – kfmfe04 Sep 19 '22 at 19:02