I implemented the function merged_tuples
for merging tuples in given order while preserving intra-tuple order. It seems that Julia isn’t able to infer the return types accurately, however (using Test.@inferred
):
julia> @inferred merged_tuples(Val((1, 2, 1, 1, 2, 2, 2, 1)), Val(((Val(1), Val(2), Val(3), Val(4)), (Val(5), Val(6), Val(7), Val(8)))))
ERROR: return type Tuple{Val{1}, Val{5}, Val{2}, Val{3}, Val{6}, Val{7}, Val{8}, Val{4}} does not match inferred return type Tuple{Val{1}, Val{5}, Val, Val, Val, Val, Val, Val}
So it seems like the types of the first few elements get inferred accurately, but the others not so much. Perhaps this is because of the count
call in merged_tuples
.
This is my implementation, with a comment for documentation:
# Merges tuples while preserving intra-tuple order, with indices
# determining where each element goes (which element of the resultant
# tuple comes from which source tuple).
#
# For example, if indices is:
# (1, 2, 1, 1, 2)
# and tuples is:
# ((11, 12, 13), (21, 22))
# the result is:
# (11, 21, 12, 13, 22)
function merged_tuples(::Val{indices}, ::Val{tuples}) where {indices, tuples}
(length(indices) == sum(length, tuples, init = 0)) || error("mismatched total size")
all(
pair -> ==(pair...),
zip(
ntuple(
let fi = firstindex(tuples)
i -> count(==(i + fi - 1), indices, init = 0)
end,
Val{length(tuples)}()),
map(length, tuples))) || error("mismatched size")
ntuple(
i ->
let j = indices[i]
tuples[j][count(==(j), indices[begin:(i - 1)], init = 0) + 1]
end,
Val{length(indices)}())
end
I’m using Julia 1.8.0-rc3 BTW.
In case it’s not clear what merged_tuples
does, here’s another implementation. It has much worse inference, though.
# A different implementation of merged_tuples.
function merged_tuples_d(::Val{indices}, ::Val{tuples}) where {indices, tuples}
local ret = Any[]
local inner_inds = zeros(length(tuples))
for i in indices
inner_inds[i] += 1
push!(ret, tuples[i][inner_inds[i]])
end
(ret...,)
end