# Mapping with Flattening - Like a Kronecker Product

I want to do something like

``````A = map(x -> [x,2*x], transpose([1,2,3]))
``````

which yields:

``````1×3 transpose(::Vector{LinearAlgebra.Transpose{Int64, Vector{Int64}}}) with eltype Vector{Int64}:
[1, 2]  [2, 4]  [3, 6]
``````

But I wanted

``````6-element Vector{Int64}:
1
2
2
4
3
6
``````

I suspect there is some one-liner (or at least very simple) way of doing this. I understand how to write a function, perhaps called KronLikeMap , that does this with 2 loops. But I can’t find anything useful in the manual.

The problem may be that I don’t know what searches to try.

1 Like
``````julia> A = reduce(vcat, map(x -> [x, 2*x], transpose([1, 2, 3])))
6-element Vector{Int64}:
1
2
2
4
3
6
``````
2 Likes

Reduce-vcat and reduce-hcat solve a bunch of my other issues.

Thanks

This is about four times faster on my machine, probably because it does less allocation. Maybe not as pretty.

``````myfill(a) = (v = Int[]; foreach(x -> push!(v, x, 2*x), a); v)
``````
4 Likes

Raf’s response is awesome. If you wanted to be even slicker you could use:

``````mapreduce(x->[x,2x], vcat, [1,2,3])
``````

Also you might not even need the transpose.

3 Likes

I’m sure there is a scientific explanation for the following, but it is mysterious to me:

``````julia> const b = 1:1000;

julia> @btime mapreduce(x->(x,2x), vcat, b);
764.033 μs (999 allocations: 7.78 MiB)

julia> @btime mapreduce(x->[x,2x], vcat, b);
784.130 μs (1999 allocations: 7.87 MiB)

julia> @btime reduce(vcat, map(x -> (x, 2*x), b));
792.793 μs (1000 allocations: 7.79 MiB)

julia> @btime reduce(vcat, map(x -> [x, 2*x], b));
23.978 μs (1002 allocations: 117.44 KiB)

julia> @btime myfill(b);
8.126 μs (11 allocations: 32.45 KiB)
``````
1 Like

`reduce(vcat, vector_of_arrays)` is fast because it has the manual performance overload:

Since it is easy to know the output element type in this case, I’d use `mapfoldl` + `append!`. It’s faster and more robust (i.e., works even if the input is empty):

``````julia> @btime reduce(vcat, map(x -> [x, 2*x], 1:1000));
30.709 μs (1002 allocations: 117.44 KiB)

julia> @btime mapfoldl(x -> (x, 2x), append!, 1:1000; init = Int[]);
9.830 μs (11 allocations: 32.45 KiB)
``````

There’s probably no need to micro-optimize this. But, it is helpful to use the information of the output vector size. `BangBang.collector` is a composable tool for encoding this.:

``````julia> using BangBang

julia> @btime finish!(append!!(collector(Vector{Int}(undef, 2000), Val(true)), (y for x in 1:1000 for y in (x, 2x))));
839.000 ns (1 allocation: 15.75 KiB)
``````
2 Likes

This variant looks simple too:
`vcat([[x,2x] for x in [1,2,3]]...)`

1 Like