Mapreduce with function that has multiple return values

I frequently run into an issue where I want to apply a function over a range of inputs and combine the output into arrays, where the function returns more than 1 value, and each return value should be collected in a different array.

If the function returns only a single argument, it is easy to use mapreduce with, e.g. vcat, to concatenate everything into a single array. Is there a built-in way to do the same for multiple return values (e.g. some kind of vcat_of_tuple)?

You can broadcast vcat itself to apply it to each element of a tuple:

julia> vcat_of_tuple = (args...) -> vcat.(args...)
#7 (generic function with 1 method)
julia> mapreduce(x -> (x, 2x), vcat_of_tuple, [1, 2, 3])
([1, 2, 3], [2, 4, 6])

This might not be the most efficient approach, though, since repeatedly calling vcat will allocate lots of temporary arrays:

julia> @btime mapreduce(x -> (x, 2x), $vcat_of_tuple, $([1, 2, 3]))
  2.139 μs (36 allocations: 1.69 KiB)

Instead, you can use mapfoldl and push! to re-use the resulting array:

julia> @btime mapfoldl(x -> (x, 2x), (args...) -> push!.(args...), $([1, 2, 3]), init=(Int[], Int[]))
  102.731 ns (8 allocations: 384 bytes)
([1, 2, 3], [2, 4, 6])
1 Like

You could steal one of the unzip implementations from https://github.com/JuliaLang/julia/pull/33515 . (I thought there was a package too but can’t find it.)

1 Like