I can create the following (length(X),) array:
[F(x) for x in X]
However, if F(x) returns an array, is there anyway way to create a multidimensional array using comprehension where each row is F(x), and the dimensions of the array are (length(X),length(F(x))
?
There are many ways to do this in Julia! Following your use of comprehensions, a simple way to turn the array output of F(x)
into a 2-dimensional array would be to concatenate the results, either with vcat
, hcat
, or the more generic cat
, and using a reduce
operation over the arguments:
F(x) = [x, x*2, x*3]
X = collect(1:5)
reduce(vcat, [F(x)' for x in X])
# 5×3 Array{Int64,2}:
# 1 2 3
# 2 4 6
# 3 6 9
# 4 8 12
# 5 10 15
Because you specifically requested a length(X)
by length(F(x))
array, the adjoint operator '
has to be used on the output of F(x)
to orient it properly for vcat
. You can also do the same with hcat
and transpose the result:
reduce(hcat, [F(x) for x in X])'
# 5×3 LinearAlgebra.Adjoint{Int64,Array{Int64,2}}:
# 1 2 3
# 2 4 6
# 3 6 9
# 4 8 12
# 5 10 15
The reduce
call is required because vcat
and hcat
concatenate together all of their arguments--if you just give them [F(x) for x in X]
, they will assume you are passing one single array of arrays and simply return that because there is nothing to concatenate.
You should also take a look at function broadcasting, a feature that sets Julia apart from many other languages. It can help reduce the verbosity of code that in other languages relies on list comprehensions. Just add a period after your function name and before the arguments to automatically broadcast the function over all of the elements of the argument!
Y = collect(2:2:10)
reduce(hcat, F.(Y))'
# 5×3 LinearAlgebra.Adjoint{Int64,Array{Int64,2}}:
# 2 4 6
# 4 8 12
# 6 12 18
# 8 16 24
# 10 20 30
As @CameronBiegnanek points out, Julia supports function composition using the ∘
operator. Composing two functions together like (G ∘ F)(x)
translates to G(F(x))
, so you can compose the adjoint
operation with your function F
like this:
reduce(vcat, (adjoint ∘ F).(X))
But this kind of operation (mapping a function over all elements of an array, then reducing all of those outputs using another function) is a common way of processing data known as a "map-reduce" operation. Julia has a built-in mapreduce
function to do just that!
mapreduce(adjoint ∘ F, vcat, X)
If F(x)
returns a tuple or a StaticArray, the upcoming Julia 1.6 will allow you to do what you're asking like this:
reinterpret(reshape, T, [F(x) for x in X])
Demo:
julia> reinterpret(reshape, Int, [(i, i+1) for i=1:4])
2×4 reinterpret(reshape, Int64, ::Vector{Tuple{Int64, Int64}}) with eltype Int64:
1 2 3 4
2 3 4 5
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With