AnyMath 文档

一维和多维数组

Julia与大多数技术计算语言一样,提供了一流的数组实现。 大多数技术计算语言都以牺牲其他容器为代价来关注它们的数组实现。 Julia不以任何特殊的方式处理数组。 数组库几乎完全在Julia本身中实现,并从编译器中获得其性能,就像用Julia编写的任何其他代码一样。 因此,也可以通过继承自定义数组类型 抽象阵列. 查看 abstractarray接口的手册部分有关实现自定义数组类型的更多详细信息。

数组是存储在多维网格中的对象的集合。 允许零维数组,请参阅 此常见问题条目。 在最一般的情况下,数组可能包含类型的对象 任何. 对于大多数计算目的,数组应该包含更具体类型的对象,例如 漂浮64Int32.

一般来说,与许多其他技术计算语言不同,Julia不希望程序以矢量化风格编写以提高性能。 Julia的编译器使用类型推断并生成标量数组索引的优化代码,允许以方便可读的风格编写程序,而不会牺牲性能,并且有时使用更少的内存。

在Julia中,函数的所有参数都是https://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_sharing[通过共享传递](即通过指针)。 一些技术计算语言按值传递数组,虽然这可以防止调用者中值的调用意外修改,但它使避免不必要的数组复制变得困难。 按照惯例,以a结尾的函数名 ! 指示它将改变或破坏它的一个或多个参数的值(例如比较, 排序排序!). Callees必须进行显式副本,以确保他们不会修改他们不打算更改的输入。 许多非变异函数是通过调用具有添加的同名函数来实现的 ! 在输入的显式副本的末尾,并返回该副本。

基本功能

功能 资料描述

eltype(A)

包含的元素的类型 A

长度(A)

中元素的数量 A

ndims(A)

的维数 A

尺寸(A)

包含以下维度的元组 A

尺寸(A,n)

的大小 A 沿尺寸 n

轴(A)

包含以下有效索引的元组 A

轴(A,n)

沿维度表示有效索引的范围 n

每个索引(A)

一个有效的迭代器,用于访问 A

步幅(A,k)

沿维度的步幅(相邻元素之间的线性索引距离) k

跨步(A)

每个维度的跨步元组

构造和初始化

提供了许多构造和初始化数组的函数。 在下面的此类函数列表中,使用 dims。.. 参数可以采用一个维度大小的元组,也可以采用一系列维度大小作为可变数量的参数传递。 大多数这些函数也接受第一个输入 T,这是数组的元素类型。 如果类型 T 省略它将默认为 漂浮64.

功能 资料描述

数组{T}(undef,dims。..)

一个未初始化的密 阵列

零(T,dims。..)

一个 阵列 全零中

一个(T,dims。..)

一个 阵列 在所有人中

trues(dims。..)

a 比特阵列与所有值 真的

假(dims。..)

a 比特阵列 与所有的价值观 错误

重塑(A,dims。..)

包含相同数据的数组 A,但尺寸不同

副本(A)

副本 A

深拷贝(A)

副本 A,递归复制其元素

类似(A,T,dims。..)

与…​…​相同类型的未初始化数组 A (密集,稀疏等。),但具有指定的元素类型和尺寸。 第二个和第三个参数都是可选的,默认为 A 如果省略。

重新解释(T,A)

与二进制数据相同的数组 A,但与元素类型 T

兰德(T,dims。..)

一个 阵列 具有随机,iid脚注:1[iid,独立且相同分布。]和均匀分布的值。 对于浮点类型 T,值位于半开区间 .

randn(T,dims...)

一个 阵列 具有随机,iid和标准正态分布值

矩阵{T}(I,m,n)

m-由-n 单位矩阵。 需要 使用线性代数.

范围(开始,停止,n)

一系列的 n 线性间隔的元件从 开始停止

填满!(A,x)

填充数组 A 与值 x

fill(x,dims...)

一个 阵列 充满了价值 x. 特别是, 填充(x) 构造零维 阵列 包含 x.

要查看我们可以将维度传递给这些函数的各种方式,请考虑以下示例:

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

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

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

这里, (2, 3) 是一个 元组而第一个参数—​元素类型—​是可选的,默认为 漂浮64.

数组文字

数组也可以直接用方括号构造;语法 [A,B,C,。..] 创建一个一维数组(即向量),其中包含逗号分隔的参数作为其元素。 元素类型(eltype,eltype)结果数组的类型由大括号内的参数类型自动确定。 如果所有的参数都是相同的类型,那么这就是它的 eltype,eltype. 如果他们都有一个共同的 促销类型然后他们得到转换为该类型使用 转换/转换并且该类型是数组的 eltype,eltype. 否则,一个可以容纳任何东西的异构数组—​a 向量{Any} --被构造;这包括字面 [] 没有给出参数的地方。 数组字面量可以键入与语法 T[A,B,C,。..] 哪里 T 是一种类型。

julia> [1, 2, 3] # An array of `Int`s
3-element Vector{Int64}:
 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 Vector{Float64}:
 1.0
 2.3
 0.8

julia> Float32[1, 2.3, 4//5] # Specify element type manually
3-element Vector{Float32}:
 1.0
 2.3
 0.8

julia> []
Any[]

连接,连接

如果方括号内的参数用单个分号分隔(;)或换行符而不是逗号,那么它们的内容是_vertically连接在一起,而不是作为元素本身使用的参数。

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

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

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

同样,如果参数由制表符或空格或双分号分隔,则它们的内容是_horizontally concatenated_在一起。

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

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

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

julia> [1;; 2;; 3;; 4]
1×4 Matrix{Int64}:
 1  2  3  4

单个分号(或换行符)和空格(或制表符)可以组合在一起,在同一时间水平和垂直连接。

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

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

julia> [[1 1]; 2 3; [4 4]]
3×2 Matrix{Int64}:
 1  1
 2  3
 4  4

空格(和制表符)的优先级高于分号,首先执行任何水平连接,然后连接结果。 另一方面,使用双分号进行水平连接,在水平连接结果之前执行任何垂直连接。

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

朱莉娅> [1:2; 4;; 1; 3:4]
3×2矩阵{Int64}:
 1  1
 2  3
 4  4

正如 ;;; 连接在第一和第二维,使用更多的分号扩展了同样的一般方案。 分隔符中的分号数指定特定维度,因此 ;;; 在第三维连接, ;;;; 在第4,等等。 较少的分号优先,因此较低的维度通常首先连接。

julia> [1; 2;; 3; 4;; 5; 6;;;
        7; 8;; 9; 10;; 11; 12]
2×3×2 Array{Int64, 3}:
[:, :, 1] =
 1  3  5
 2  4  6

[:, :, 2] =
 7   9  11
 8  10  12

与之前一样,水平连接的空格(和制表符)的优先级高于任何数量的分号。 因此,更高维数组也可以通过首先指定它们的行来编写,其元素以类似于其布局的方式在文本上排列:

julia> [1 3 5
        2 4 6;;;
        7 9 11
        8 10 12]
2×3×2 Array{Int64, 3}:
[:, :, 1] =
 1  3  5
 2  4  6

[:, :, 2] =
 7   9  11
 8  10  12

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

[:, :, 2, 1] =
 3  4

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

[:, :, 2, 2] =
 7  8

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

[:, :, 2, 1] =
 3  4

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

[:, :, 2, 2] =
 7  8

虽然它们都意味着第二维的串联,但空格(或制表符)和 ;; 不能出现在同一个数组表达式中,除非双分号只是作为"行延续"字符。 这允许单个水平连接跨越多行(而不会将换行符解释为垂直连接)。

julia> [1 2 ;;
       3 4]
1×4 Matrix{Int64}:
 1  2  3  4

终止分号也可用于添加尾随长度1维。

julia> [1;;]
1×1 Matrix{Int64}:
 1

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

更一般地说,串联可以通过 貓!功能。 这些语法是函数调用的简写,而函数调用本身就是方便函数:

语法 功能 资料描述

貓!

沿维度连接输入数组 k

[A;B;C;。..]

vcat的

速记 猫(A...;dims=1)

[A B C...]

hcat,hcat

速记 猫(A...;dims=2)

[A B;C D;。..]

[医hvcat]

同时垂直和水平连接

[A;C;;B;D;;;。..]

[医hvncat]

同时n维连接,其中分号数表示要连接的维度

类型化数组字面量

可以使用以下语法构造具有特定元素类型的数组 T[A,B,C,。..]. 这将构造一个具有元素类型的1-d数组 T,初始化为包含元素 A, B, C 等。 例如, 任何[x,y,z] 构造一个可以包含任何值的异构数组。

串联语法可以类似地以类型作为前缀,以指定结果的元素类型。

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

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

理解,理解

理解提供了一种通用而强大的构造数组的方法。 理解语法类似于数学中的集合构造符号:

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

这种形式的含义是, F(x,y,...) 使用变量进行评估 x, y 等。 取其给定值列表中的每个值。 值可以指定为任何可迭代对象,但通常是如下范围 1:n2:(n-1),或值的显式数组,如 [1.2, 3.4, 5.7]. 结果是一个n-d密集数组,其维度是变量范围的维度的串联 rx,rx, ry 等。 而每个 F(x,y,...) 求值返回标量。

下面的示例计算当前元素及其左邻和右邻沿一维网格的加权平均值:

julia> x = rand(8)
8-element Vector{Float64}:
 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 Vector{Float64}:
 0.736559
 0.57468
 0.685417
 0.912429
 0.8446
 0.656511

生成的数组类型取决于计算元素的类型,就像 数组文字做。 为了显式地控制类型,可以在理解之前添加一个类型。 例如,我们可以通过写入请求单精度的结果:

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

后面的所有逗号分隔表达式 被解释为范围。 添加括号可以让我们将第三个参数添加到 地图:

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

生成器通过内部函数实现。 就像语言中其他地方使用的内部函数一样,来自封闭范围的变量可以在内部函数中"捕获"。 例如, sum(p[i]-q[i]for i=1:n) 捕获三个变量 p, qn 从封闭范围。 捕获的变量可能会带来性能挑战;请参阅 性能提示

生成器和理解中的范围可以通过写入多个来依赖于以前的范围 关键词:

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

在这种情况下,结果总是1-d。

生成的值可以使用 如果 关键字:

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

索引

索引到n维数组的一般语法 A 是:

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

每个 I_k 可以是标量整数,整数数组或任何其他 支持的索引。 这包括 结肠 (:)要选择整个维度内的所有索引,表单的范围 a:ca:b:c 选择连续或跨段的子节,以及布尔数组,以在其 真的 指数。

如果所有索引都是标量,则结果 X 是数组中的单个元素 A. 否则的话, X 是具有与所有索引的维数之和相同的维数的数组。

如果所有指数 I_k 是矢量,例如,那么形状 X 会是 (长度(I_1),长度(I_2),。..,长度(I_n)),与位置 i_1,i_2,。..,i_nX 包含值 A[I_1[i_1],I_2[i_2],。..,I_n[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

朱莉娅>A[1, 2, 1, 1] # 所有标量指数
3

朱莉娅>A[[1, 2], [1], [1, 2], [1]] # 所有矢量索引
2×1×2×1阵列{Int64, 4}:
[:, :, 1, 1] =
 1
 2

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

朱莉娅>A[[1, 2], [1], [1, 2], 1] # 索引类型的混合
2×1×2阵列{Int64, 3}:
[:, :, 1] =
 1
 2

[:, :, 2] =
 5
 6

请注意在最后两种情况下,结果数组的大小是如何不同的。

如果 I_1 被改变为二维矩阵,则 X 成为一个 n+1-形状的维数组 (大小(I_1,1),大小(I_1,2),长度(I_2),...,长度(I_n)). 矩阵增加一个维度。

例子::

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

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

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

地点 i_1,i_2,i_3,。..,我_{n+1} 包含值在 A[I_1[i_1,i_2],I_2[i_3],...,I_n[i_{n+1}]]. 所有标量索引的维度都将被删除。 例如,如果 J 是一个索引数组,然后是 A[2,J,3] 是大小的数组 尺寸(J). 其 jth元素由 A[2,J[j],3].

作为此语法的特殊部分, 结束 关键字可用于表示索引括号内每个维度的最后一个索引,这取决于被索引的最内层数组的大小。 索引语法没有 结束 关键字相当于调用 getindex,getindex:

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 Matrix{Int64}:
 6  10
 7  11

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

索引分配

在n维数组中赋值的一般语法 A 是:

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

每个 I_k 可以是标量整数,整数数组或任何其他 支持的索引。 这包括 结肠 (:)要选择整个维度内的所有索引,请使用表单的范围 a:ca:b:c 选择连续或跨段的子节,以及布尔数组,以选择它们的元素 真的 指数。

如果所有指数 I_k 是整数,那么location中的值 I_1,I_2,。..,I_nA 被复盖的值 X, 转换/转换ing到 eltype,eltypeA 如有必要。

如果有索引 I_k 本身是一个数组,然后右手边 X 也必须是与索引结果具有相同形状的数组 A[I_1,I_2,。..,I_n] 或元素个数相同的向量。 位置中的值 I_1[i_1],I_2[i_2],。..,I_n[i_n]A 被值复盖 X[i_1,i_2,。..,i_n],必要时转换。 元素赋值运算符 .= 可用于 广播 X 在选定的位置:

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

正如在 索引结束 关键字可用于表示索引括号内每个维度的最后一个索引,这取决于被分配到的数组的大小。 索引赋值语法没有 结束 关键字相当于调用 setindex!:

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

例子::

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

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

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

朱莉娅>x
3×3矩阵{Int64}:
 -1  -4   7
 -2  -5   8
  3   6  -9

支持的索引类型

在表达式中 A[I_1,I_2,。..,I_n],各 I_k 可以是标量索引、标量索引数组或表示标量索引数组的对象,并且可以通过以下方式转换为 to_indices:

  1. 个标量索引。 默认情况下,这包括: **非布尔整数

* xref:base/arrays.adoc#Base.IteratorsMD.CartesianIndex[+CartesianIndex{N}+`s,表现得像一个 `N-跨越多个维度的整数元组(详见下文)

  1. 标量索引的数组。 这包括: **向量和整数的多维数组

*空数组,如 [],不选择任何元素,例如 A[[]] (不要与之混淆 A[]) *范围如 a:ca:b:c,从 ac (含) *任何自定义的标量索引数组,它是 抽象阵列 *数组 CartesianIndex{N} (详情见下文)

  1. 一个表示标量索引数组的对象,可以通过 to_indices. 默认情况下,这包括: ** 冒号() (:),表示整个维度内或整个数组中的所有索引

*布尔值数组,它在它们的位置选择元素。 真的 指数(详情见下文)

一些例子:

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

julia> A[4]
7

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

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

julia> A[[]]
Int64[]

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

朱莉娅>A[2,:]
3元素向量{Int64}:
  3
  9
 15

朱莉娅>A[:,3]
3元素向量{Int64}:
 13
 15
 17

朱莉娅>A[:,3:3]
3×1矩阵{Int64}:
 13
 15
 17

笛卡尔指数

特别节目 CartesianIndex{N} 对象表示一个标量索引,其行为类似于 N-跨越多个维度的整数元组。 例如:

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

单独考虑,这可能看起来相对微不足道; [医]CartesianIndex 简单地将多个整数集合到一个表示单个多维索引的对象中。 当与其他索引形式和迭代器结合使用时 [医]CartesianIndexes,但是,这可以产生非常优雅和高效的代码。 见 迭代,以及一些更高级的例子,请参阅https://julialang.org/blog/2016/02/iteration[这篇关于多维算法和迭代的博客文章]。

数组的 CartesianIndex{N} 也支持。 它们表示每个跨度的标量索引的集合 N 维度,启用有时称为逐点索引的索引形式。 例如,它允许从第一个"页面"访问对角线元素 A 从上面:

julia> page = A[:, :, 1]
4×4 Matrix{Int64}:
 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 Vector{Int64}:
  1
  6
 11
 16

这可以用更简单的方式来表达 点广播并通过将其与正常整数索引组合(而不是提取第一个 页面A 作为单独的步骤)。 它甚至可以与一个 : 在同一时间从两页中提取两条对角线:

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

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

警告 [医]CartesianIndex 和阵列的 [医]CartesianIndex结束 关键字来表示维度的最后一个索引。 不要使用 结束 在索引表达式中,可能包含 [医]CartesianIndex 或其阵列。

逻辑索引

通常被称为逻辑索引或带有逻辑掩码的索引,由布尔数组索引选择其值所在的索引处的元素 真的. 通过布尔向量进行索引 B 实际上与通过返回的整数向量进行索引相同 查找(B). 同样,索引由a N-维布尔数组与由 +CartesianIndex{N}+s它的值在哪里 真的. 逻辑索引必须是与它索引到的维度形状相同的数组,或者它必须是唯一提供的索引,并且与它索引到的数组的一维重塑视图的形状相匹配。 通常,直接使用布尔数组作为索引而不是首先调用更有效 芬德尔.

julia> x = reshape(1:12, 2, 3, 2)
2×3×2 reshape(::UnitRange{Int64}, 2, 3, 2) with eltype Int64:
[:, :, 1] =
 1  3  5
 2  4  6

[:, :, 2] =
 7   9  11
 8  10  12

julia> x[:, [true false; false true; true false]]
2×3 Matrix{Int64}:
 1  5   9
 2  6  10

julia> mask = map(ispow2, x)
2×3×2 Array{Bool, 3}:
[:, :, 1] =
 1  0  0
 1  1  0

[:, :, 2] =
 0  0  0
 1  0  0

julia> x[mask]
4-element Vector{Int64}:
 1
 2
 4
 8

julia> x[vec(mask)] == x[mask] # we can also index with a single Boolean vector
true

指数数目

笛卡尔索引

索引到一个普通的方法 N-维数组是使用精确 N 索引;每个索引在其特定维度中选择位置。 例如,在三维阵列 A=兰德(4,3,2), A[2,3,1] 将在数组的第一个"页面"中选择第三列的第二行中的数字。 这通常被称为_cartesian indexing_。

线性索引

当只有一个索引时 i 被提供,该索引不再表示数组的特定维度中的位置。 相反,它选择 i使用线性跨越整个数组的列主迭代顺序的元素。 这被称为_linear indexing_。 它基本上将数组视为已被重塑为一维向量 维克.

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

julia> A[5]
7

朱莉娅>vec(A)[5]
7

数组中的线性索引 A 可以转换为一个 [医]CartesianIndex 对于笛卡尔索引与 CartesianIndices(A)[i] (见 [医笛卡尔]),以及一组 N 笛卡尔指数可以转换为线性指数 LinearIndices(A)[i_1,i_2,...,i_N] (见 线性;线性).

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

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

需要注意的是,这些转换的性能存在非常大的不对称性。 将线性索引转换为一组笛卡尔索引需要除以并取余数,而另一种方式只是乘法和加法。 在现代处理器中,整数除法可以比乘法慢10-50倍。 而有些数组—​比如 阵列本身-使用线性内存块实现,并在实现中直接使用线性索引,其他数组-如 对角线--需要全套笛卡尔索引来进行查找(参见 xref:base/arrays.adoc#Base.IndexStyle[索引样式 自省哪个是哪个)。

警告遍历数组的所有索引时,最好遍历 每个索引(A)而不是 1:长度(A). 这不仅在以下情况下会更快 A[医]索引,但它也将支持具有自定义索引的数组,例如https://github.com/JuliaArrays/OffsetArrays.jl如果只需要值,那么最好直接迭代数组,即 对于a在A.

省略和额外索引

除了线性索引,一个 N-维数组可以用更少或更多的索引 N 某些情况下的指数。

如果未编入索引的尾随维度都是长度为1,则可以省略索引。 换句话说,只有当那些省略的索引对于一个界内索引表达式只有一个可能的值时,才可以省略尾随索引。 例如,具有大小的四维数组 (3, 4, 2, 1) 可能只用三个索引进行索引,因为跳过的维度(第四个维度)的长度为1。 请注意,线性索引优先于此规则。

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

当省略_all_索引时 A[],这个语义提供了一个简单的习惯用法来检索数组中的唯一元素,同时确保只有一个元素。

同样,超过 N 如果超出数组维度的所有索引都是 1 (或者更一般地说是 轴(A,d) 哪里 d 是那个特定的维数)。 这允许向量像单列矩阵一样被索引,例如:

julia> A = [8, 6, 7]
3-element Vector{Int64}:
 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

当您需要每个元素的值而不是索引时,将使用第一个构造。 在第二构造, i 将是一个 Int型 如果 A 是具有快速线性索引的数组类型;否则,它将是一个 [医]CartesianIndex:

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)

注意与 对于i=1:长度(A),迭代与 每个索引提供迭代任何数组类型的有效方法。 此外,这还支持具有自定义索引的泛型数组,例如https://github.com/JuliaArrays/OffsetArrays.jl[OffsetArrays]。

数组特性

如果你写一个自定义 抽象阵列类型,您可以指定它具有快速线性索引使用

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

此设置将导致 每个索引 迭代过一个 我的阵列 要使用整数。 如果不指定此特性,则默认值 IndexCartesian() 被使用。

数组和矢量化运算符和函数

数组支持以下运算符:

  1. 一元算术 — -, +

  2. 二进制算术 — -, +, *, /, \, ^

  3. 比较 — ==, !=, ([医伊萨普罗克斯]),

为了方便地对数学和其他操作进行矢量化,Julia 提供点语法 f.(args...),例如 罪。(x)敏。(x,y),用于对数组或数组和标量的混合进行元素运算(a 广播操作);当与其他点调用结合时,这些具有"融合"成一个循环的额外优点,例如。 罪。(cos.(x)).

此外,_every_二进制运算符支持 点版本可应用于数组(以及数组和标量的组合) 融合广播业务,例如 z.==罪。(x.*y).

请注意,比较如 == 对整个数组进行操作,给出一个布尔值答案。 使用点运算符,如 .== 用于元素比较。 (对于比较操作,如 <,_only_元素 .< 版本适用于数组。)

还要注意两者之间的区别 麦克斯(a,b),其 广播s 麦克斯elementwise over ab,而 最大(a),其中找到内的最大值 a. 同样的关系也适用于 敏。(a,b)最低(a).

广播

对不同大小的数组执行逐元素二进制操作有时很有用,例如向矩阵的每列添加一个向量。 一种低效的方法是将向量复制到矩阵的大小:

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

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

当尺寸变大时,这是浪费的,所以Julia提供 广播,它在不使用额外内存的情况下扩展数组参数中的单例维度以匹配其他数组中的相应维度,并应用给定的函数elementwise:

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

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

julia> broadcast(+, a, b)
2×2 Matrix{Float64}:
 1.71056  0.847604
 1.73659  0.873631

虚线运算符.+.* 等同于 广播 呼叫(除了它们融合,作为 如上所述)。 还有一个 广播!指定显式目标的函数(也可以通过以下方式以融合方式访问 .= 分配)。 事实上, f.(args...) 相当于 广播(f,args...),提供方便的语法广播任何功能(点语法)。 嵌套的"点调用" f。(。..) (包括致电 .+ 等) 数学运算和初等函数#man-dot-operators【自动熔断】成单 广播 打电话。

此外, 广播不仅限于数组(请参阅函数文档);它还处理标量,元组和其他集合。 默认情况下,只有一些参数类型被视为标量,包括(但不限于) 电话号码s, 字符串s, 符号s, 类型s, 功能s和一些常见的单例如 失踪什么都没有. 所有其他参数都被迭代或索引到elementwise中。

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

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

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

有时,您希望通常参与广播的容器(如数组)能够"保护"广播迭代其所有元素的行为。 通过将其放置在另一个容器内(如单个元素 元组)广播会将其视为单个值。

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中的基数组类型是抽象类型 抽象阵列{T,N}. 它由维度的数量参数化 N 和元素类型 T. [医文摘]和 [医抽象矩阵]是1-d和2-d情况的别名。 上的操作 抽象阵列 对象是使用更高级别的运算符和函数定义的,其方式与底层存储无关。 这些操作通常可以作为任何特定数组实现的回退正常工作。

抽象阵列 类型包含任何模糊的类似数组的东西,它的实现可能与传统数组有很大不同。 例如,元素可以根据请求计算而不是存储。 然而,任何具体 抽象阵列{T,N} 类型一般应至少实现 尺寸(A))(返回 Int型 元组), xref:base/arrays.adoc#Base.getindex-Tuple{Type,%20Vararg{Any}}[getindex(A,i)getindex(A,i1,。..,在);可变数组也应该实现 setindex!. 建议这些操作具有几乎恒定的时间复杂度,否则某些数组函数可能会出乎意料地慢。 混凝土类型通常还应提供 类似(A方法,用于为 副本等失位操作。 不管怎样 抽象阵列{T,N} 在内部表示, T 是_integer_indexing返回的对象类型(A[1,。.., 1],当 A 不是空的)和 N 应该是由返回的元组的长度 大小. 有关定义自定义的更多详细信息 抽象阵列 实现,请参阅 接口章节中的数组接口指南

[医]密度射线 是一个抽象的子类型 抽象阵列 旨在包括元素以列主顺序连续存储的所有数组(请参阅 性能提示中的附加说明)。 该 阵列类型是 [医]密度射线; 向量资料矩阵是1-d和2-d情况的别名。 很少有操作是专门为 阵列 超越所有人所需要的 抽象阵列s;数组库的大部分是以通用的方式实现的,允许所有自定义数组的行为类似。

子阵列 是一个专业的 抽象阵列 它通过与原始数组共享内存而不是通过复制它来执行索引。 A 子阵列 是用 查看函数,其调用方式与 getindex,getindex(带有数组和一系列索引参数)。 的结果 查看看起来和…​…​的结果一样。 getindex,getindex,除了数据留在原地。 查看将输入索引向量存储在 子阵列 对象,稍后可用于间接索引原始数组。 通过把 @意见宏在表达式或代码块前面,任何 数组[...] 该表达式中的切片将被转换为创建一个 子阵列 视图代替。

比特阵列s是节省空间的"打包"布尔数组,每个布尔值存储一位。 它们可以类似于 数组{Bool} 数组(每个布尔值存储一个字节),并且可以通过 数组(bitarray)BitArray(数组),分别。

如果数组存储在内存中,元素之间有明确定义的空格(步进),则它是"跨步"的。 具有支持的元素类型的跨步数组可以通过简单地传递它来传递给外部(非Julia)库,如BLAS或LAPACK。 指针和每个维度的步幅。 该 步幅(A,d)是沿维度元素之间的距离 d. 例如,内置 阵列 返回者 兰特(5,7,2) 其元素按列主顺序连续排列。 这意味着第一个维度的步幅-同一列中元素之间的间距-是 1:

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

julia> stride(A, 1)
1

第二个维度的步幅是同一行中元素之间的间距,跳过单个列中尽可能多的元素(5). 同样,在两个"页面"(在第三维中)之间跳跃需要跳过 5*7 == 35 元素。 该 xref:base/arrays.adoc#Base.strides[跨步 这个数组的元组是这三个数字的元组:

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

在这种特定情况下,跳过的元素的数量_in memory_与跳过的元素的数量相匹配。 这只是连续数组的情况,如 阵列 (和其他 [医]密度射线 亚型)并且在一般情况下不是真的。 具有范围索引的视图是_non-contiguous_strided数组的一个很好的例子;考虑 V=@查看A[1:3:4, 2:2:6, 2:-1:1]. 此视图 V 指与内存相同的内存 A 但正在跳过并重新安排它的一些元素。 第一维的步幅 V3 因为我们只从原始数组中选择每三行:

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

julia> stride(V, 1)
3

这个视图类似地从我们的原始列中选择其他列 A --因此,当在第二维的索引之间移动时,它需要跳过相当于两个五元素列:

julia> stride(V, 2)
10

第三维是有趣的,因为它的顺序是相反的! 因此,要从第一个"页面"到第二个页面,它必须在内存中去_backwards_,因此它在这个维度上的步幅是负的!

julia> stride(V, 3)
-35

这意味着 指针V 实际上是指着 A内存块,它指的是内存中向后和向前的元素。 查看 跨步数组接口指南有关定义自己的跨步数组的更多详细信息。 StridedVector碌录潞陆StridedMatrix禄忙猫潞镁鹿芦掳戮掳是许多被认为是跨步数组的内置数组类型的方便别名,允许它们分派选择专门的实现,这些实现只使用指针和跨步调用高度优化和优化的BLAS和LAPACK函数。

值得强调的是,跨步是关于内存中的偏移而不是索引。 如果您希望在线性(单索引)索引和笛卡尔(多索引)索引之间进行转换,请参阅 线性;线性[医笛卡尔].