将 2d 元组添加到 Julia 中的 2d 数组

Vin*_*nod 3 tuples arithmetic-expressions matrix julia

如何在 Julia 中将二维元组添加到二维矩阵?

    t1 = ((10,20),(30,40)); #2d immutable tuple 
    a = [1 2;3 4] #2d matrix 
    a .+ t1 
Run Code Online (Sandbox Code Playgroud)

抛出错误:

MethodError: no method matching +(::Int64, ::Tuple{Int64, Int64})
Closest candidates are:
  +(::Any, ::Any, ::Any, ::Any...) at operators.jl:560
  +(::T, ::T) where T<:Union{Int128, Int16, Int32, Int64, Int8, UInt128, UInt16, UInt32, UInt64, UInt8} at int.jl:87
  +(::Integer, ::Ptr) at pointer.jl:161
  ...
Stacktrace:
 [1] _broadcast_getindex_evalf
   @ .\broadcast.jl:648 [inlined]
 [2] _broadcast_getindex
   @ .\broadcast.jl:621 [inlined]
 [3] getindex
   @ .\broadcast.jl:575 [inlined]
 [4] copy
   @ .\broadcast.jl:922 [inlined]
 [5] materialize(bc::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{2}, Nothing, typeof(+), Tuple{Matrix{Int64}, Tuple{Tuple{Int64, Int64}, Tuple{Int64, Int64}}}})
   @ Base.Broadcast .\broadcast.jl:883
 [6] top-level scope
   @ REPL[15]:1
Run Code Online (Sandbox Code Playgroud)

是否存在向量/矩阵加法方法?显然我可以使用 for 循环逐个元素相加。

cbk*_*cbk 7

啊,所以这里的问题是,当你调用t1“二维元组”时,它实际上不是;它是一个嵌套元组,一个元组的元组,因此与您的二维数组(实际上一个二维对象而不仅仅是数组的数组)没有真正的可比性。

\n

如果您想将二维数组添加到一个不可变对象中,该对象可以像Tuple真正的二维一样进行堆栈分配,那么您可以使用StaticArrays.jl包,它提供了不可变SArray类型:

\n
julia> a = [1 2; 3 4]\n2\xc3\x972 Matrix{Int64}:\n 1  2\n 3  4\n\njulia> using StaticArrays\n\njulia> t1 = SA[10 20; 30 40]\n2\xc3\x972 SMatrix{2, 2, Int64, 4} with indices SOneTo(2)\xc3\x97SOneTo(2):\n 10  20\n 30  40\n\njulia> a + t1\n2\xc3\x972 SMatrix{2, 2, Int64, 4} with indices SOneTo(2)\xc3\x97SOneTo(2):\n 11  22\n 33  44\n
Run Code Online (Sandbox Code Playgroud)\n

但是,如果出于某种原因您确实想坚持嵌套而不是多维,那么让我们也将数组嵌套起来

\n
julia> t1 = ((10,20),(30,40)) #tuple-of-tuples\n((10, 20), (30, 40))\n\njulia> a = [[1,2],[3,4]] #vector-of-vectors\n2-element Vector{Vector{Int64}}:\n [1, 2]\n [3, 4]\n
Run Code Online (Sandbox Code Playgroud)\n

在这种情况下你可以通过递归轻松解决

\n
add(a,b) = a + b\nadd(a::Vector, b::NTuple{N}) where N = [add(a[i],b[i]) for i in 1:N]\nadd(a::NTuple{N}, b::Vector) where N = [add(a[i],b[i]) for i in 1:N]\n
Run Code Online (Sandbox Code Playgroud)\n
julia> add(a,t1)\n2-element Vector{Vector{Int64}}:\n [11, 22]\n [33, 44]\n
Run Code Online (Sandbox Code Playgroud)\n

这种方法还可以扩展到任意深度嵌套的对象:

\n
julia> a = [[[1,2],[3,4]],[[5,6],[7,8]]]\n2-element Vector{Vector{Vector{Int64}}}:\n [[1, 2], [3, 4]]\n [[5, 6], [7, 8]]\n\njulia> t1 = (((10,20),(30,40)),((50,60),(70,80)))\n(((10, 20), (30, 40)), ((50, 60), (70, 80)))\n\njulia> add(a,t1)\n2-element Vector{Vector{Vector{Int64}}}:\n [[11, 22], [33, 44]]\n [[55, 66], [77, 88]]\n
Run Code Online (Sandbox Code Playgroud)\n

不幸的是,真正的多维数组和在不支持真正的多维数组的语言中使用向量的向量的常见黑客之间存在广泛的语义混淆。

\n


phi*_*ler 5

@cbk 已经解释了嵌套数组为何不等同于多维结构。但是,如果您的结构已经嵌套,您当然可以将添加内容编写为嵌套广播。从(我相信)Julia 1.6 开始,就有了独立“广播运算符”的语法,可以使用它:

\n
julia> t1 = ((10,20),(30,40))\n((10, 20), (30, 40))\n\njulia> a = [[1,2],[3,4]]\n2-element Vector{Vector{Int64}}:\n [1, 2]\n [3, 4]\n\njulia> broadcast(.+, a, t1)\n2-element Vector{Vector{Int64}}:\n [11, 22]\n [33, 44]\n
Run Code Online (Sandbox Code Playgroud)\n

如果a是 a Matrix,您可以在 上执行相同操作eachrow

\n
julia> a = [1 2;3 4]\n2\xc3\x972 Matrix{Int64}:\n 1  2\n 3  4\n\njulia> broadcast(.+, eachrow(a), t1)\n2-element Vector{Vector{Int64}}:\n [11, 22]\n [33, 44]\n
Run Code Online (Sandbox Code Playgroud)\n

(在本例中,map相当于broadcast。)

\n