Julia:为什么在重塑数组后需要收集输出?

Pig*_*gna 3 arrays multidimensional-array reshape julia

A = collect(reshape(1:16, 4, 4))
4×4 Array{Int64,2}:
 1  5   9  13
 2  6  10  14
 3  7  11  15
 4  8  12  16
Run Code Online (Sandbox Code Playgroud)

怎么有必要collect?不能reshape自动输出4x4 Array{Int64, 2}?在哪些情况下我需要一个Base.ReshapedArray{Int64,2,UnitRange{Int64},Tuple{}}

Mat*_* B. 7

这里的关键是reshape通常提供原始数据结构的视图 ......它只是改变了将数据视为新形状的方式.在这种情况下,您的原始数据结构就是范围1:16.

范围是非常紧凑和高效的阵列状物体.他们不需要存储所有元素; 相反,他们只是做基本的数学运算来计算每个元素.以这种方式,它们实际上可以比等价(如)更快.在大多数情况下,您可以在任何地方使用范围.这是您不应指定或在函数签名中的主要原因- 而您(和其他库作者)应该使用,如果您不需要内存表示.Arraycollect(1:16)Arrayarg::Array::Matrix::AbstractArray::AbstractMatrix

有两个主要的例外:范围是完全不可变的 - 您不能分配或修改它们的任何元素.所以这就是为什么你可能想collect进入一个原因Array.另一种情况是,如果您正在调用不支持Julia通用灵活性的C/Fortran /外部库.在这些情况下,他们经常需要内存表示,如Array.

同样如此reshape(1:16, 4, 4).类似于范围如何在运行中计算其元素,在这种情况下,ReshapedArray将传递给它的索引转换回原始数组(1:16)的原始形状,然后它访问该原始数组.它非常有效地做到这一点.事实上,如果你偷看幕后你可以看到它只存储4个整数:

julia> dump(reshape(1:16, 4, 4))
Base.ReshapedArray{Int64,2,UnitRange{Int64},Tuple{}}
  parent: UnitRange{Int64}
    start: Int64 1
    stop: Int64 16
  dims: Tuple{Int64,Int64}
    1: Int64 4
    2: Int64 4
  mi: Tuple{} ()
Run Code Online (Sandbox Code Playgroud)

它需要知道的是UnitRange父级的开始和停止(1-16),以及它被重新整形的维度(4x4).其他一切都是按需完成的.正如你要注意的那样,这里的大小并不重要 - reshape(a:b, y, z)总是只存储4个整数,无论​​它有多大a:b.