[[(p[i],p[i+1]) for i in 1:2:length(a)] for p in permutations(a)
if all(p[1:2:end-2] .< p[3:2:end]) && all(p[1:2:end] .< p[2:2:end])]
gives for a = ["a", "b", "c", "d"]
:
3-element Vector{Vector{Tuple{String, String}}}:
[("a", "b"), ("c", "d")]
[("a", "c"), ("b", "d")]
[("a", "d"), ("b", "c")]
and gives for a = ["a", "b", "c", "d", "e", "f"]
:
15-element Vector{Vector{Tuple{String, String}}}:
[("a", "b"), ("c", "d"), ("e", "f")]
[("a", "b"), ("c", "e"), ("d", "f")]
[("a", "b"), ("c", "f"), ("d", "e")]
[("a", "c"), ("b", "d"), ("e", "f")]
[("a", "c"), ("b", "e"), ("d", "f")]
[("a", "c"), ("b", "f"), ("d", "e")]
[("a", "d"), ("b", "c"), ("e", "f")]
[("a", "d"), ("b", "e"), ("c", "f")]
[("a", "d"), ("b", "f"), ("c", "e")]
[("a", "e"), ("b", "c"), ("d", "f")]
[("a", "e"), ("b", "d"), ("c", "f")]
[("a", "e"), ("b", "f"), ("c", "d")]
[("a", "f"), ("b", "c"), ("d", "e")]
[("a", "f"), ("b", "d"), ("c", "e")]
[("a", "f"), ("b", "e"), ("c", "d")]
The comprehension basically goes over all permutations and gets single representative from each equivalence group of the solution’s symmetry group (if math lingo unclear, the actual one-liner is simpler to understand).
But perhaps a simple recursive function is quicker:
function trans(a)
n = length(a)
# next two conditions can be commented out as they shouldn't
# occur in normal usage
n == 0 && return Vector{Tuple{eltype(a),eltype(a)}}[]
isodd(n) && error("must be even length")
n == 2 && return [(a[1], a[2])]
res = Vector{Tuple{eltype(a),eltype(a)}}[]
for i=2:n
append!(res,
vcat((a[1],a[i]),t) for t in trans([a[j] for j=2:n if j ≠ i]))
end
return res
end
If optimization really critical, preallocation possible using formula for number of elements: result_length = factorial(n) / ( factorial(n÷2) * 2^(n÷2) )
.