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

时间:2017-10-30 17:01:00

标签: arrays multidimensional-array julia reshape

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

collect怎么办?可以reshape自动输出4x4 Array{Int64, 2}吗?在哪些情况下我需要Base.ReshapedArray{Int64,2,UnitRange{Int64},Tuple{}}

1 个答案:

答案 0 :(得分:7)

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

范围是非常紧凑和高效的阵列式对象。他们不需要存储他们所有的元素;相反,他们只是做基本的数学运算来计算每个元素。通过这种方式,他们实际上可以更快而不是Array - 相当于(collect(1:16))。在大多数情况下,您可以在Array工作的任何地方使用范围。这是您不应在函数签名中指定arg::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{} ()

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