为什么 [1:2] 不等于 Array[1:2]

7

我正在按照Wikibook学习Julia,但我不明白为什么下面的两个命令会产生不同的结果:

julia> [1:2]
1-element Array{UnitRange{Int64},1}:
 1:2

julia> Array[1:2]
1-element Array{Array,1}:
 [1,2]

如果在Wikibook中有我没有看到的解释,我很抱歉,我简要地查看了一下,但没有找到。


@user2864740 Array[[1:2]] 给出了另一个结果(一个包含数组和范围的数组),但这对我来说是有意义的。也许我没有理解的是为什么 [ a:b ] 是特殊的? - Jonathan H
1个回答

6

Type[a] 运行 convert 函数来处理元素,Range 和 Array(collect)之间存在着简单的转换。所以 Array[1:2]1:2 转换成一个数组,然后生成像那样的对象数组。这与为什么 Float64[1;2;3] 是一个 Float64 数组是相同的。


前面的部分回答了错误的问题。糟糕...

a:b 不是一个数组,它是一个 UnitRange。为什么要为 A = a:b 创建一个数组呢?只需要两个数字就可以存储它,并且您可以基本免费地计算任何 iA[i]。使用数组将占用与 b-a 成比例的内存量,因此对于更大的数组,分配时间会很长,而分配 UnitRange 实际上是免费的。

在 Julia 中,这些类型被称为惰性迭代器。LinSpace 是另一个例子。另一组有趣的类型是特殊矩阵类型:为什么要使用多个数组来存储 DiagonalUniformScaling 操作符作为恒等矩阵,同时只存储一个值(它的比例),以使 A-kI 更高效。

由于 Julia 具有强大的类型系统,没有理由将所有这些东西都制作成数组。相反,您可以将它们制作成专门的类型,这些类型将像数组一样操作(*+ 等)和索引,但实际上并不是数组。这将使它们占用更少的内存,并且更快。如果您需要数组,只需调用 collect(A)full(A)


我意识到您发布了一些更具体的内容。原因在于 Array[1:2] 调用了数组的 getindex 函数。这个 getindex 函数对 Range 进行了特殊的分派,以便它“像被数组索引”一样运作(请参见前面的讨论)。所以这是“特别处理的”,但实际上它只是像其他函数一样分派来像数组一样运作。无论 A 是什么,[A] 都会给出一个 typeof(A) 数组,所以这里没有什么魔法。



如果我表达不清楚,我很抱歉;我完全理解为什么1:2是一个对象而不是数组。我不明白的是为什么Array[1:2]似乎会扩展其参数。 - Jonathan H
因此,从您的编辑中可以看出,两个结果之间的差异是由于针对惰性迭代器的getindex重载引起的。任何语言都有其特殊性,但这个问题很难理解;这也引出了一个问题,为什么A[1:2] == A[[1:2...]]呢? - Jonathan H
1
哦,我想我还是误读了你的问题并回答了其他的东西,哈哈。Type[a] 在元素上运行 convert,而在 RangeArray (collect) 之间有一个简单的转换。这就是为什么 Float64[1;2;3] 是一个 Float64 数组的原因:逐个元素进行转换。 - Chris Rackauckas
那最后的评论是我认为缺失的一部分,谢谢你的解释 :) 你能否重新排列你的答案,把最后一部分放在前面,这样我就可以确认它是答案了! - Jonathan H
我按要求重新排列了答案。 - Chris Rackauckas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接