# 多维数组

## 基本函数

eltype(A)A 中元素的类型
length(A)A 中元素的数量
ndims(A)A 的维数
size(A)一个包含 A 各个维度上元素数量的元组
size(A,n)An 维中的元素数量
axes(A)一个包含 A 有效索引的元组
axes(A,n)n 维有效索引的范围
eachindex(A)一个访问 A 中每一个位置的高效迭代器
stride(A,k)在第 k 维上的间隔（stride）（相邻元素间的线性索引距离）
strides(A)包含每一维上的间隔（stride）的元组

## 构造和初始化

Julia 提供了许多用于构造和初始化数组的函数。在下列函数中，参数 dims ... 可以是一个包含维数大小的元组，也可以表示用任意个参数传递的一系列维数大小值。大部分函数的第一个参数都表示数组的元素类型 T 。如果类型 T 被省略，那么将默认为 Float64

Array{T}(undef, dims...)一个没有初始化的密集 Array
zeros(T, dims...)一个全零 Array
ones(T, dims...)一个元素均为 1 的 Array
trues(dims...)一个每个元素都为 trueBitArray
falses(dims...)一个每个元素都为 falseBitArray
reshape(A, dims...)一个包含跟 A 相同数据但维数不同的数组
copy(A)拷贝 A
deepcopy(A)深拷贝，即拷贝 A，并递归地拷贝其元素
similar(A, T, dims...)一个与A具有相同类型（这里指的是密集，稀疏等）的未初始化数组，但具有指定的元素类型和维数。第二个和第三个参数都是可选的，如果省略则默认为元素类型和 A 的维数。
reinterpret(T, A)A 具有相同二进制数据的数组，但元素类型为 T
rand(T, dims...)一个随机 Array，元素值是 $[0, 1)$ 半开区间中的均匀分布且服从一阶独立同分布 [1]
randn(T, dims...)一个随机 Array，元素为标准正态分布，服从独立同分布
Matrix{T}(I, m, n)m-by-n 单位阵。 需要 using LinearAlgebra for I.
range(start, stop=stop, length=n)startstop 的带有 n 个线性间隔元素的范围
fill!(A, x)用值 x 填充数组 A
fill(x, dims...)一个被值 x 填充的 Array

julia> zeros(Int8, 2, 3)
2×3 Array{Int8,2}:
0  0  0
0  0  0

julia> zeros(Int8, (2, 3))
2×3 Array{Int8,2}:
0  0  0
0  0  0

julia> zeros((2, 3))
2×3 Array{Float64,2}:
0.0  0.0  0.0
0.0  0.0  0.0

## Array literals

julia> [1,2,3] # An array of Ints
3-element Array{Int64,1}:
1
2
3

julia> promote(1, 2.3, 4//5) # This combination of Int, Float64 and Rational promotes to Float64
(1.0, 2.3, 0.8)

julia> [1, 2.3, 4//5] # Thus that's the element type of this Array
3-element Array{Float64,1}:
1.0
2.3
0.8

julia> []
Any[]

### Concatenation

If the arguments inside the square brackets are separated by semicolons (;) or newlines instead of commas, then their contents are vertically concatenated together instead of the arguments being used as elements themselves.

julia> [1:2, 4:5] # Has a comma, so no concatenation occurs. The ranges are themselves the elements
2-element Array{UnitRange{Int64},1}:
1:2
4:5

julia> [1:2; 4:5]
4-element Array{Int64,1}:
1
2
4
5

julia> [1:2
4:5
6]
5-element Array{Int64,1}:
1
2
4
5
6

Similarly, if the arguments are separated by tabs or spaces, then their contents are horizontally concatenated together.

julia> [1:2  4:5  7:8]
2×3 Array{Int64,2}:
1  4  7
2  5  8

julia> [[1,2]  [4,5]  [7,8]]
2×3 Array{Int64,2}:
1  4  7
2  5  8

julia> [1 2 3] # Numbers can also be horizontally concatenated
1×3 Array{Int64,2}:
1  2  3

Using semicolons (or newlines) and spaces (or tabs) can be combined to concatenate both horizontally and vertically at the same time.

julia> [1 2
3 4]
2×2 Array{Int64,2}:
1  2
3  4

julia> [zeros(Int, 2, 2) [1; 2]
[3 4]            5]
3×3 Array{Int64,2}:
0  0  1
0  0  2
3  4  5

More generally, concatenation can be accomplished through the cat function. These syntaxes are shorthands for function calls that themselves are convenience functions:

cat沿着 s 的第 k 维拼接数组
[A; B; C; ...]vcatshorthand for cat(A...; dims=1)
[A B C ...]hcatshorthand for cat(A...; dims=2)
[A B; C D; ...]hvcatsimultaneous vertical and horizontal concatenation

### Typed array literals

julia> [[1 2] [3 4]]
1×4 Array{Int64,2}:
1  2  3  4

julia> Int8[[1 2] [3 4]]
1×4 Array{Int8,2}:
1  2  3  4

## Comprehensions

（数组）推导提供了构造数组的通用且强大的方法。其语法类似于数学中的集合构造的写法：

A = [ F(x,y,...) for x=rx, y=ry, ... ]

julia> x = rand(8)
8-element Array{Float64,1}:
0.843025
0.869052
0.365105
0.699456
0.977653
0.994953
0.41084
0.809411

julia> [ 0.25*x[i-1] + 0.5*x[i] + 0.25*x[i+1] for i=2:length(x)-1 ]
6-element Array{Float64,1}:
0.736559
0.57468
0.685417
0.912429
0.8446
0.656511

The resulting array type depends on the types of the computed elements just like array literals do. In order to control the type explicitly, a type can be prepended to the comprehension. For example, we could have requested the result in single precision by writing:

Float32[ 0.25*x[i-1] + 0.5*x[i] + 0.25*x[i+1] for i=2:length(x)-1 ]

## 生成器表达式

julia> sum(1/n^2 for n=1:1000)
1.6439345666815615

julia> map(tuple, 1/(i+j) for i=1:2, j=1:2, [1:4;])
ERROR: syntax: invalid iteration specification

for 后面所有逗号分隔的表达式都被解释为范围。 添加括号让我们可以向 map 中添加第三个参数：

julia> map(tuple, (1/(i+j) for i=1:2, j=1:2), [1 3; 2 4])
2×2 Array{Tuple{Float64,Int64},2}:
(0.5, 1)       (0.333333, 3)
(0.333333, 2)  (0.25, 4)

Generators are implemented via inner functions. Just like inner functions used elsewhere in the language, variables from the enclosing scope can be "captured" in the inner function. For example, sum(p[i] - q[i] for i=1:n) captures the three variables p, q and n from the enclosing scope. Captured variables can present performance challenges; see performance tips.

julia> [(i,j) for i=1:3 for j=1:i]
6-element Array{Tuple{Int64,Int64},1}:
(1, 1)
(2, 1)
(2, 2)
(3, 1)
(3, 2)
(3, 3)

julia> [(i,j) for i=1:3 for j=1:i if i+j == 4]
2-element Array{Tuple{Int64,Int64},1}:
(2, 2)
(3, 1)

## 索引

X = A[I_1, I_2, ..., I_n]

julia> A = reshape(collect(1:16), (2, 2, 2, 2))
2×2×2×2 Array{Int64,4}:
[:, :, 1, 1] =
1  3
2  4

[:, :, 2, 1] =
5  7
6  8

[:, :, 1, 2] =
9  11
10  12

[:, :, 2, 2] =
13  15
14  16

julia> A[1, 2, 1, 1] # all scalar indices
3

julia> A[[1, 2], [1], [1, 2], [1]] # all vector indices
2×1×2×1 Array{Int64,4}:
[:, :, 1, 1] =
1
2

[:, :, 2, 1] =
5
6

julia> A[[1, 2], [1], [1, 2], 1] # a mix of index types
2×1×2 Array{Int64,3}:
[:, :, 1] =
1
2

[:, :, 2] =
5
6

julia> A = reshape(collect(1:16), (2, 2, 2, 2));

julia> A[[1 2; 1 2]]
2×2 Array{Int64,2}:
1  2
1  2

julia> A[[1 2; 1 2], 1, 2, 1]
2×2 Array{Int64,2}:
5  6
5  6

X = getindex(A, I_1, I_2, ..., I_n)

julia> x = reshape(1:16, 4, 4)
4×4 reshape(::UnitRange{Int64}, 4, 4) with eltype Int64:
1  5   9  13
2  6  10  14
3  7  11  15
4  8  12  16

julia> x[2:3, 2:end-1]
2×2 Array{Int64,2}:
6  10
7  11

julia> x[1, [2 3; 4 1]]
2×2 Array{Int64,2}:
5  9
13  1

## Indexed Assignment

A[I_1, I_2, ..., I_n] = X

A[I_1, I_2, ..., I_n] .= X

setindex!(A, X, I_1, I_2, ..., I_n)

julia> x = collect(reshape(1:9, 3, 3))
3×3 Array{Int64,2}:
1  4  7
2  5  8
3  6  9

julia> x[3, 3] = -9;

julia> x[1:2, 1:2] = [-1 -4; -2 -5];

julia> x
3×3 Array{Int64,2}:
-1  -4   7
-2  -5   8
3   6  -9

## 支持的索引类型

1. 标量索引。默认情况下，这包括：
• 非布尔的整数
• CartesianIndex {N}s，其行为类似于跨越多个维度的 N 维整数元组（详见下文）s, which behave like an N-tuple of integers spanning multiple dimensions (see below for more details)
2. 标量索引数组。这包括：
• 整数向量和多维整数数组
• [] 这样的空数组，它不选择任何元素
• a:ca:b:c 的范围，从 ac（包括）选择连续或间隔的部分元素
• 任何自定义标量索引数组，它是 AbstractArray 的子类型
• CartesianIndex{N} 数组（详见下文）
3. 一个表示标量索引数组的对象，可以通过to_indices转换为这样的对象。 默认情况下，这包括：
• Colon() (:)，表示整个维度内或整个数组中的所有索引
• 布尔数组，选择其中值为 true 的索引对应的元素（更多细节见下文）

julia> A = reshape(collect(1:2:18), (3, 3))
3×3 Array{Int64,2}:
1   7  13
3   9  15
5  11  17

julia> A[4]
7

julia> A[[2, 5, 8]]
3-element Array{Int64,1}:
3
9
15

julia> A[[1 4; 3 8]]
2×2 Array{Int64,2}:
1   7
5  15

julia> A[[]]
Int64[]

julia> A[1:2:5]
3-element Array{Int64,1}:
1
5
9

julia> A[2, :]
3-element Array{Int64,1}:
3
9
15

julia> A[:, 3]
3-element Array{Int64,1}:
13
15
17

### 笛卡尔索引

julia> A = reshape(1:32, 4, 4, 2);

julia> A[3, 2, 1]
7

julia> A[CartesianIndex(3, 2, 1)] == A[3, 2, 1] == 7
true

julia> page = A[:,:,1]
4×4 Array{Int64,2}:
1  5   9  13
2  6  10  14
3  7  11  15
4  8  12  16

julia> page[[CartesianIndex(1,1),
CartesianIndex(2,2),
CartesianIndex(3,3),
CartesianIndex(4,4)]]
4-element Array{Int64,1}:
1
6
11
16

julia> A[CartesianIndex.(axes(A, 1), axes(A, 2)), 1]
4-element Array{Int64,1}:
1
6
11
16

julia> A[CartesianIndex.(axes(A, 1), axes(A, 2)), :]
4×2 Array{Int64,2}:
1  17
6  22
11  27
16  32
Warning

CartesianIndex and arrays of CartesianIndex are not compatible with the end keyword to represent the last index of a dimension. Do not use end in indexing expressions that may contain either CartesianIndex or arrays thereof.

### Logical indexing

Often referred to as logical indexing or indexing with a logical mask, indexing by a boolean array selects elements at the indices where its values are true. Indexing by a boolean vector B is effectively the same as indexing by the vector of integers that is returned by findall(B). Similarly, indexing by a N-dimensional boolean array is effectively the same as indexing by the vector of CartesianIndex{N}s where its values are true. A logical index must be a vector of the same length as the dimension it indexes into, or it must be the only index provided and match the size and dimensionality of the array it indexes into. It is generally more efficient to use boolean arrays as indices directly instead of first calling findall.

julia> x = reshape(1:16, 4, 4)
4×4 reshape(::UnitRange{Int64}, 4, 4) with eltype Int64:
1  5   9  13
2  6  10  14
3  7  11  15
4  8  12  16

julia> x[[false, true, true, false], :]
2×4 Array{Int64,2}:
2  6  10  14
3  7  11  15

4×4 Array{Bool,2}:
1  0  0  0
1  0  0  0
0  0  0  0
1  1  0  1

5-element Array{Int64,1}:
1
2
4
8
16

### Number of indices

#### Cartesian indexing

The ordinary way to index into an N-dimensional array is to use exactly N indices; each index selects the position(s) in its particular dimension. For example, in the three-dimensional array A = rand(4, 3, 2), A[2, 3, 1] will select the number in the second row of the third column in the first "page" of the array. This is often referred to as cartesian indexing.

#### Linear indexing

When exactly one index i is provided, that index no longer represents a location in a particular dimension of the array. Instead, it selects the ith element using the column-major iteration order that linearly spans the entire array. This is known as linear indexing. It essentially treats the array as though it had been reshaped into a one-dimensional vector with vec.

julia> A = [2 6; 4 7; 3 1]
3×2 Array{Int64,2}:
2  6
4  7
3  1

julia> A[5]
7

julia> vec(A)[5]
7

A linear index into the array A can be converted to a CartesianIndex for cartesian indexing with CartesianIndices(A)[i] (see CartesianIndices), and a set of N cartesian indices can be converted to a linear index with LinearIndices(A)[i_1, i_2, ..., i_N] (see LinearIndices).

julia> CartesianIndices(A)[5]
CartesianIndex(2, 2)

julia> LinearIndices(A)[2, 2]
5

It's important to note that there's a very large assymmetry in the performance of these conversions. Converting a linear index to a set of cartesian indices requires dividing and taking the remainder, whereas going the other way is just multiplies and adds. In modern processors, integer division can be 10-50 times slower than multiplication. While some arrays — like Array itself — are implemented using a linear chunk of memory and directly use a linear index in their implementations, other arrays — like Diagonal — need the full set of cartesian indices to do their lookup (see IndexStyle to introspect which is which). As such, when iterating over an entire array, it's much better to iterate over eachindex(A) instead of 1:length(A). Not only will the former be much faster in cases where A is IndexCartesian, but it will also support OffsetArrays, too.

#### Omitted and extra indices

In addition to linear indexing, an N-dimensional array may be indexed with fewer or more than N indices in certain situations.

Indices may be omitted if the trailing dimensions that are not indexed into are all length one. In other words, trailing indices can be omitted only if there is only one possible value that those omitted indices could be for an in-bounds indexing expression. For example, a four-dimensional array with size (3, 4, 2, 1) may be indexed with only three indices as the dimension that gets skipped (the fourth dimension) has length one. Note that linear indexing takes precedence over this rule.

julia> A = reshape(1:24, 3, 4, 2, 1)
3×4×2×1 reshape(::UnitRange{Int64}, 3, 4, 2, 1) with eltype Int64:
[:, :, 1, 1] =
1  4  7  10
2  5  8  11
3  6  9  12

[:, :, 2, 1] =
13  16  19  22
14  17  20  23
15  18  21  24

julia> A[1, 3, 2] # Omits the fourth dimension (length 1)
19

julia> A[1, 3] # Attempts to omit dimensions 3 & 4 (lengths 2 and 1)
ERROR: BoundsError: attempt to access 3×4×2×1 reshape(::UnitRange{Int64}, 3, 4, 2, 1) with eltype Int64 at index [1, 3]

julia> A[19] # Linear indexing
19

When omitting all indices with A[], this semantic provides a simple idiom to retrieve the only element in an array and simultaneously ensure that there was only one element.

Similarly, more than N indices may be provided if all the indices beyond the dimensionality of the array are 1 (or more generally are the first and only element of axes(A, d) where d is that particular dimension number). This allows vectors to be indexed like one-column matrices, for example:

julia> A = [8,6,7]
3-element Array{Int64,1}:
8
6
7

julia> A[2,1]
6

## 迭代

for a in A
# Do something with the element a
end

for i in eachindex(A)
# Do something with i and/or A[i]
end

julia> A = rand(4,3);

julia> B = view(A, 1:3, 2:3);

julia> for i in eachindex(B)
@show i
end
i = CartesianIndex(1, 1)
i = CartesianIndex(2, 1)
i = CartesianIndex(3, 1)
i = CartesianIndex(1, 2)
i = CartesianIndex(2, 2)
i = CartesianIndex(3, 2)

for i = 1:length(A) 相比，eachindex 提供了一种迭代任何数组类型的有效方法。

## Array traits

Base.IndexStyle(::Type{<:MyArray}) = IndexLinear()

## Array and Vectorized Operators and Functions

1. 一元运算符 – -, +
2. 二元运算符 – -, +, *, /, \, ^
3. 比较操作符 – ==, !=, ≈ (isapprox), ≉

## 广播

julia> a = rand(2,1); A = rand(2,3);

julia> repeat(a,1,3)+A
2×3 Array{Float64,2}:
1.20813  1.82068  1.25387
1.56851  1.86401  1.67846

julia> broadcast(+, a, A)
2×3 Array{Float64,2}:
1.20813  1.82068  1.25387
1.56851  1.86401  1.67846

julia> b = rand(1,2)
1×2 Array{Float64,2}:
0.867535  0.00457906

2×2 Array{Float64,2}:
1.71056  0.847604
1.73659  0.873631

Dotted operators such as .+ and .* are equivalent to broadcast calls (except that they fuse, as described above). There is also a broadcast! function to specify an explicit destination (which can also be accessed in a fusing fashion by .= assignment). In fact, f.(args...) is equivalent to broadcast(f, args...), providing a convenient syntax to broadcast any function (dot syntax). Nested "dot calls" f.(...) (including calls to .+ etcetera) automatically fuse into a single broadcast call.

Additionally, broadcast is not limited to arrays (see the function documentation); it also handles scalars, tuples and other collections. By default, only some argument types are considered scalars, including (but not limited to) Numbers, Strings, Symbols, Types, Functions and some common singletons like missing and nothing. All other arguments are iterated over or indexed into elementwise.

julia> convert.(Float32, [1, 2])
2-element Array{Float32,1}:
1.0
2.0

julia> ceil.(UInt8, [1.2 3.4; 5.6 6.7])
2×2 Array{UInt8,2}:
0x02  0x04
0x06  0x07

julia> string.(1:3, ". ", ["First", "Second", "Third"])
3-element Array{String,1}:
"1. First"
"2. Second"
"3. Third"

Sometimes, you want a container (like an array) that would normally participate in broadcast to be "protected" from broadcast's behavior of iterating over all of its elements. By placing it inside another container (like a single element Tuple) broadcast will treat it as a single value.

julia> ([1, 2, 3], [4, 5, 6]) .+ ([1, 2, 3],)
([2, 4, 6], [5, 7, 9])

julia> ([1, 2, 3], [4, 5, 6]) .+ tuple([1, 2, 3])
([2, 4, 6], [5, 7, 9])

## 实现

Julia 中的基本数组类型是抽象类型 AbstractArray{T,N}。它通过维数 N 和元素类型 T 进行参数化。AbstractVectorAbstractMatrix 是一维和二维情况下的别名。AbstractArray 对象的操作是使用更高级别的运算符和函数定义的，其方式独立于底层存储。这些操作可以正确地被用于任何特定数组实现的回退操作。

AbstractArray 类型包含任何模糊类似的东西，它的实现可能与传统数组完全不同。例如，可以根据请求而不是存储来计算元素。但是，任何具体的 AbstractArray{T,N} 类型通常应该至少实现 size(A)（返回 Int 元组），getindex(A,i)getindex(A,i1,...,iN)；可变数组也应该实现 setindex!。建议这些操作具有几乎为常数的时间复杂性，或严格说来 Õ(1) 复杂性，否则某些数组函数可能出乎意料的慢。具体类型通常还应提供 similar(A,T=eltype(A),dims=size(A)) 方法，用于为 copy 分配类似的数组和其他位于当前数组空间外的操作。无论在内部如何表示 AbstractArray{T,N}T 是由 整数 索引返回的对象类型（A[1, ..., 1]，当 A 不为空），N 应该是 size 返回的元组的长度。有关定义自定义 AbstractArray 实现的更多详细信息，请参阅接口章节中的数组接口导则

DenseArray is an abstract subtype of AbstractArray intended to include all arrays where elements are stored contiguously in column-major order (see additional notes in Performance Tips). The Array type is a specific instance of DenseArray; Vector and Matrix are aliases for the 1-d and 2-d cases. Very few operations are implemented specifically for Array beyond those that are required for all AbstractArrays; much of the array library is implemented in a generic manner that allows all custom arrays to behave similarly.

SubArrayAbstractArray 的特例，它通过与原始数组共享内存而不是复制它来执行索引。 使用view 函数创建 SubArray，它的调用方式与getindex 相同（作用于数组和一系列索引参数）。 view 的结果看起来与 getindex 的结果相同，只是数据保持不变。 view 将输入索引向量存储在 SubArray 对象中，该对象稍后可用于间接索引原始数组。 通过将 @views 宏放在表达式或代码块之前，该表达式中的任何 array [...] 切片将被转换为创建一个 SubArray 视图。

BitArray 是节省空间“压缩”的布尔数组，每个比特（bit）存储一个布尔值。 它们可以类似于 Array{Bool} 数组（每个字节（byte）存储一个布尔值），并且可以分别通过 Array(bitarray)BitArray(array) 相互转换。

An array is "strided" if it is stored in memory with well-defined spacings (strides) between its elements. A strided array with a supported element type may be passed to an external (non-Julia) library like BLAS or LAPACK by simply passing its pointer and the stride for each dimension. The stride(A, d) is the distance between elements along dimension d. For example, the builtin Array returned by rand(5,7,2) has its elements arranged contiguously in column major order. This means that the stride of the first dimension — the spacing between elements in the same column — is 1:

julia> A = rand(5,7,2);

julia> stride(A,1)
1

The stride of the second dimension is the spacing between elements in the same row, skipping as many elements as there are in a single column (5). Similarly, jumping between the two "pages" (in the third dimension) requires skipping 5*7 == 35 elements. The strides of this array is the tuple of these three numbers together:

julia> strides(A)
(1, 5, 35)

In this particular case, the number of elements skipped in memory matches the number of linear indices skipped. This is only the case for contiguous arrays like Array (and other DenseArray subtypes) and is not true in general. Views with range indices are a good example of non-contiguous strided arrays; consider V = @view A[1:3:4, 2:2:6, 2:-1:1]. This view V refers to the same memory as A but is skipping and re-arranging some of its elements. The stride of the first dimension of V is 3 because we're only selecting every third row from our original array:

julia> V = @view A[1:3:4, 2:2:6, 2:-1:1];

julia> stride(V, 1)
3

This view is similarly selecting every other column from our original A — and thus it needs to skip the equivalent of two five-element columns when moving between indices in the second dimension:

julia> stride(V, 2)
10

The third dimension is interesting because its order is reversed! Thus to get from the first "page" to the second one it must go backwards in memory, and so its stride in this dimension is negative!

julia> stride(V, 3)
-35

This means that the pointer for V is actually pointing into the middle of A's memory block, and it refers to elements both backwards and forwards in memory. See the interface guide for strided arrays for more details on defining your own strided arrays. StridedVector and StridedMatrix are convenient aliases for many of the builtin array types that are considered strided arrays, allowing them to dispatch to select specialized implementations that call highly tuned and optimized BLAS and LAPACK functions using just the pointer and strides.

It is worth emphasizing that strides are about offsets in memory rather than indexing. If you are looking to convert between linear (single-index) indexing and cartesian (multi-index) indexing, see LinearIndices and CartesianIndices.

• 1iid，独立同分布