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{}}
?
答案 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
有多大。