Julia 中的多维数组理解

Multi-dimensional array comprehension in Julia

我可以创建以下 (length(X),) 数组:

[F(x) for x in X]

但是,如果 F(x) returns 是一个数组,有没有办法使用推导式创建多维数组,其中每一行都是 F(x),数组的维度是 (length(X),length(F(x))?

在 Julia 中有很多方法可以做到这一点!在您使用理解之后,将 F(x) 的数组输出转换为二维数组的一种简单方法是连接结果,或者对参数进行 vcat, hcat, or the more generic cat, and using a reduce 操作:

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

因为您特别请求 length(X) by length(F(x)) 数组,所以必须在 F(x) 的输出上使用伴随运算符 ' 以正确定位它 vcat。您也可以对 hcat 执行相同操作并转置结果:

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

调用 reduce 是必需的,因为 vcathcat 将它们的所有参数连接在一起——如果你只给它们 [F(x) for x in X],它们会认为你是传递一个单一的数组数组并简单地 return 那是因为没有什么可以连接的。

您还应该看看 function broadcasting,这是一个让 Julia 有别于许多其他语言的特性。它可以帮助减少其他语言中依赖于列表理解的代码的冗长性。只需在函数名称之后和参数之前添加一个句点,即可自动将函数广播到参数的所有元素上!

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

高级:函数组合

正如@CameronBiegnanek 指出的那样,Julia 支持使用 运算符的 function composition。将两个函数组合在一起,如 (G ∘ F)(x) 转换为 G(F(x)),因此您可以将 adjoint 操作与函数 F 组合在一起,如下所示:

reduce(vcat, (adjoint ∘ F).(X))

但是这种操作(映射一个数组所有元素的函数,然后reducing所有这些输出使用另一个函数) 是一种常见的数据处理方式,称为“map-reduce”操作。 Julia 有一个 built-in mapreduce 函数可以做到这一点!

mapreduce(adjoint ∘ F, vcat, X)

如果 F(x) returns 一个元组或 StaticArray,即将推出的 Julia 1.6 将允许您像这样执行您的要求:

reinterpret(reshape, T, [F(x) for x in X])

演示:

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