Introducing Julia/Arrays and tuples
Storage: 数组 和 元组
[编辑]在 Julia 中,相关项的组(related groups)通常存储在数组(Arrays)、元组(Tuples)或字典(Dictionaries)中。
数组可用于存储向量和矩阵。本节集中讨论数组和元组;有关字典的更多信息参见 Dictionaries and Sets。
数组
[编辑]数组是元素的有序集合。它通常用方括号和逗号分隔的项表示。可以创建已满或为空的数组,以及保存不同类型的值或仅限于特定类型的值的数组。
在 Julia 中,数组被用作列表(lists)、向量(vectors)、表(tables)和矩阵(matrices)。
一维数组充当矢量或列表;二维数组可以用作表或矩阵;三维数组和多维数组同样被看作是多维矩阵。
创建数组
[编辑]创建简单数组
[编辑]下面的代码演示如何创建一个简单的一维数组:
julia> a = [1, 2, 3, 4, 5] 5-element Array{Int64,1}: 1 2 3 4 5
Julia 通知您 ("5-element Array{Int64,1}") 表示您创建了一个有 5 个元素(每个元素都是 64 位整数)的一维数组。并将变量 a
绑定到该数组。 请注意,这个过程很智能:例如,如果其中一个元素看起来像一个浮点数,您将得到 Float64 的数组:
julia> a1 = [1, 2, 3.0, 4, 5] 5-element Array{Float64,1}: 1.0 2.0 3.0 4.0 5.0
类似的对于各种字符串:
julia> s = ["this", "is", "an", "array", "of", "strings"] 6-element Array{String,1}: "this" "is" "an" "array" "of" "strings"
返回一个字符串的数组。
以及:
julia> trigfuns = [sin, cos, tan] 3-element Array{Function,1}: sin cos tan
返回一个包含 Julia 函数的数组。
有许多不同的方法来创建数组:
您可以使它们成为空的、未初始化的、满的、基于序列的、稀疏的、密集的等等。这取决于手头的任务。
未初始化的
[编辑]可以使用 Array{type}(dims)
指定数组的类型和维数 (注意是大写的 "A"), 将该类型放入大括号中,并将长度放在括号中。 undef
表示数组尚未初始化为已知的值。
julia> array = Array{Int64}(undef, 5) 5-element Array{Int64,1}: 4520632328 4614616448 4520668544 4520632328 4615451376 4294967362
julia> array3 = Array{Int64}(undef, 2, 2, 2) 2×2×2 Array{Int64,3}: [:, :, 1] = 4452254272 4452255728 4452256400 4456808080 [:, :, 2] = 4456808816 4452255728 4456808816 4452254272
随机的数字提醒您已经创建了一个未初始化的数组,但还没有用任何合理的信息填充它。
包含任意类型元素的数组
[编辑]可以使用不同类型的元素创建数组:
julia> [1, "2", 3.0, sin, pi] 5-element Array{Any, 1}: 1 "2" 3.0 sin π = 3.1415926535897...
在这里,数组有五个元素,但它们是一个奇怪的混合:数字、字符串、函数、常量。因此 Julia 创建了一个类型为 Any 的数组:
julia> typeof(ans) Array{Any,1}
空数组
[编辑]要创建特定类型的数组,还可以使用类型定义和方括号:
julia> Int64[1, 2, 3, 4] 4-element Array{Int64,1}: 1 2 3 4
如果您认为可以通过在声明类型数组时偷偷输入错误类型的值来愚弄 Julia,结果不会如您所愿:
julia> Int64[1, 2, 3, 4, 5, 6, 7, 8, 9, 10.1] ERROR: InexactError()
你也可以用这种方式创建空数组:
julia> b = Int64[] 0-element Array{Int64,1}
julia> b = String[] 0-element Array{String,1}
julia> b = Float64[] 0-element Array{Float64,1}
创建二维数组和矩阵
[编辑]如果在定义阵列时省略逗号,则可以快速创建二维阵列。下面是一个单行、多列数组:
julia> [1 2 3 4] 1x4 Array{Int64,2}: 1 2 3 4
注意第一行输出的 1x4 {...,2}
可以使用分号添加另一行:
julia> [1 2 3 4 ; 5 6 7 8] 2x4 Array{Int64,2}: 1 2 3 4 5 6 7 8
行向量和列向量
[编辑]对比二者: [1,2,3,4,5]
和 [1 2 3 4 5]
.
使用逗号,此数组可以称为“列向量”,由5行和1列组成:
julia> [1, 2, 3, 4, 5] 5-element Array{Int64,1}: 1 2 3 4 5
但使用空格时,此数组可以称为“行向量”,由1行和5列组成:
julia> [1 2 3 4 5] 1x5 Array{Int64,2}: 1 2 3 4 5
注意 {Int64,2}
这里告诉你 这是一个包含 Int64 (有 1 行和 5 列)的二维数组。在这两种情况下,它们都是标准Julia数组。
这样创建的数组可以用作矩阵:
julia> [1 2 3; 4 5 6] 2x3 Array{Int64,2}: 1 2 3 4 5 6
当然,您可以创建具有3个或更多维度的数组/矩阵。
有许多函数允许您一次性完成创建和填充数组。见 Creating and filling an array.
注意 Julia 是如何区分 Array{Float64,1}
和 Array{Float64,2}
:
julia> x = rand(5) 5-element Array{Float64,1}: 0.4821773161183929 0.5811789456966778 0.7852806713801641 0.23626682918327369 0.6777187748570226
julia> x = rand(5, 1) 5×1 Array{Float64,2}: 0.0723474801859294 0.6314375868614579 0.21065681560040828 0.8300724654838343 0.42988769728089804
Julia 提供 Vector
and Matrix
构造函数 。不过这些只是未初始化的一维数组和二维数组的别名:
julia> Vector(undef, 5) 5-element Array{Any,1}: #undef #undef #undef #undef #undef julia> Matrix(undef, 5, 5) 5x5 Array{Any,2}: #undef #undef #undef #undef #undef #undef #undef #undef #undef #undef #undef #undef #undef #undef #undef #undef #undef #undef #undef #undef #undef #undef #undef #undef #undef
使用范围对象 创建数组
[编辑]在 Julia 中, 冒号 (:
) 有很多种用法。一种用途是定义数字的范围(Range) 和序列。可以通过直接键入范围对象来创建该对象:
julia> 1:10 1:10
这种形式下看起来可能不是很有用,但它为 Julia 中任何需要数字范围或序列的工作提供了原材料。
你可以在循环表达式中这么使用:
julia> for n in 1:10 print(n) end 12345678910
或者使用 collect()
来建立一个由这些数字构成的数组:
julia> collect(1:10) 10-element Array{Int64,1}: 1 2 3 4 5 6 7 8 9 10
你也不必起始或结束使用整数:
julia> collect(3.5:9.5) 7-element Array{Float64,1}: 3.5 4.5 5.5 6.5 7.5 8.5 9.5
还有一个范围对象的三块版本 Start:Step:Stop,它允许您指定步长,而非默认的1。
例如,这将构建一个数组,该数组的元素从0到100,每10步执行一次:
julia> collect(0:10:100) 11-element Array{Int64,1}: 0 10 20 30 40 50 60 70 80 90 100
要降序而不是升序,您必须使用负的 step 值:
julia> collect(4:-1:1) 4-element Array{Int64,1}: 4 3 2 1
代替使用 collect()
来创建一个范围的数组, 你可以在最后一个元素使用省略号运算符 (...
) :
julia> [1:6...] 6-element Array{Int64,1}: 1 2 3 4 5 6
(省略号运算符 ...
有时候被叫做 splat 运算符,它代表一系列参数)
然而, collect()
速度更快,并且是将范围转换为数组的推荐方法。
不过您可以在Julia中的许多情况下使用 Range 对象,并且不必总是将它们扩展为数组。
范围 进一步使用
[编辑]另一个有用的函数是 range()
, 它构造一个从开始值到结束值的范围对象,该对象采用一定大小的特定数量的 step。由于 Julia 通过组合关键字 step()
, length()
以及 stop()
来为您计算缺少的部分,因此不必计算所有信息。
例如,要通过 12 步 从 1 到 100,请执行以下操作:
julia> range(1, length=12, stop=100) 1.0:9.0:100.0
或者从1开始走10步,在100点或之前停下来:
julia> range(1, stop=100, step=10) 1:10:91
如果您确实希望它以数组的形式出现,可以使用 Range 对象来构建一个数组:
julia> collect(range(1, length=12, stop=100)) 12-element Array{Float64,1}: 1.0 10.0 19.0 28.0 37.0 46.0 55.0 64.0 73.0 82.0 91.0 100.0
请注意,它提供了 Float64 数组,而不是 整型数组,即使这些值可能是整数。
对于对数范围(有时称为'log space'),你可以用简单的 Range 对象并且用 exp10
函数广播(broadcast)到该范围的所有元素。
julia> exp10.(range(2.0, stop=3.0, length=5)) 5-element Array{Float64,1}: 100.0 177.82794100389228 316.22776601683796 562.341325190349 1000.0
见 Broadcasting and dot syntax.
在 Range 对象中使用 step()
来指出 step 的大小:
julia> step(range(1, length=10, stop=100)) 11.0
如果知道开始和步骤,但不知道结束,并且知道需要多少元素,请使用 range()
:
julia> range(1, step=3, length=20) |> collect 20-element Array{Int64,1}: 1 4 7 10 13 16 19 22 25 28 31 34 37 40 43 46 49 52 55 58
对 Range 中的值 collect
[编辑]如您所见,如果未在 for
循环中使用 Range 对象,(如果需要)则可以使用 collect()
直接从Range对象获取所有值:
julia> collect(0:5:100) 21-element Array{Int64,1}: 0 5 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100
不过,在处理范围之前,不必总是将范围转换为数组,因为通常可以直接迭代。例如,您不必这样写:
for i in collect(1:6)
println(i)
end
1
2
3
4
5
6
因为如果你不用collect()
它也能很好地运行(而且可能更快):
for i in 1:6
println(i)
end
1
2
3
4
5
6
使用推导和生成器创建数组
[编辑]创建数组的一种有用方法是使用推导 (在 Comprehensions 中具体说明),其中每个元素都可以使用小型计算生成。
例如,要创建5个数字的数组,请执行以下操作:
julia> [n^2 for n in 1:5] 5-element Array{Int64,1}: 1 4 9 16 25
使用两个迭代器,可以轻松创建二维阵列或矩阵:
julia> [r * c for r in 1:5, c in 1:5] 5x5 Array{Int64,2}: 1 2 3 4 5 2 4 6 8 10 3 6 9 12 15 4 8 12 16 20 5 10 15 20 25
您可以在末尾添加 if
测试以筛选(或保留)通过测试的值:
julia> [i^2 for i=1:10 if i != 5] 9-element Array{Int64,1}: 1 4 9 16 36 49 64 81 100
生成器的表达式类似,并且可以类似的方式使用:
julia> collect(x^2 for x in 1:10) 10-element Array{Int64,1}: 1 4 9 16 25 36 49 64 81 100
julia> collect(x^2 for x in 1:10 if x != 1) 9-element Array{Int64,1}: 4 9 16 25 36 49 64 81 100
生成器表达式的优点是,它们在需要时生成值,而不是先构建一个数组来保存它们。
创建和填满一个数组
[编辑]有许多函数允许您创建具有特定内容的数组。当使用二维数组作为矩阵时,这些方法非常有用:
- zeros(m, n)
创建具有m行和n列的零数组/矩阵:
julia> zeros(2, 3) 2x3 Array{Float64,2}: 0.0 0.0 0.0 0.0 0.0 0.0
如有需要可以指定零的类型:
julia> zeros(Int64, 3, 5) 3×5 Array{Int64,2}: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- ones(m, n)
创建一个全为1的 m 行 n列的数组或矩阵
julia> ones(2, 3) 2x3 Array{Float64,2}: 1.0 1.0 1.0 1.0 1.0 1.0
- rand(m, n)
创建全是随机数的 m 行 n 列的矩阵:
julia> rand(2, 3) 2×3 Array{Float64,2}: 0.488552 0.657078 0.895564 0.0190633 0.0120305 0.772106
- rand(range, m, n)
创建给定范围的随机数矩阵:
julia> rand(1:6, 3, 3) 3x3 Array{Int64,2}: 4 4 1 3 2 3 6 3 3
- randn(m, n)
创建 m 行 n 列矩阵。矩阵中充满均值为0,标准差为1的正态分布随机数。
除了 zeros()
, ones()
等函数之外,还有 trues()
, falses()
, fill()
, 以及 fill!()
函数。
trues()
和 falses()
函数用布尔值 true 或 false 填充数组:
julia> trues(3, 4) 3x4 BitArray{2}: true true true true true true true true true true true true
注意这个结果是 BitArray。
你可以使用 fill()
来创建具有特定值 (即重复数组)的数组,请执行以下操作:
julia> fill(42, 9) 9-element Array{Int64,1}: 42 42 42 42 42 42 42 42 42 julia> fill("hi", 2, 2) 2x2 Array{String,2}: "hi" "hi" "hi" "hi"
fill!()
有一个感叹号标记 (!
, 或者叫"bang") 警告您即将更改现有数组的内容。(这在 Julia 中是一种有效的指示)。
julia> a = zeros(10) 10-element Array{Float64,1}: 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 julia> fill!(a, 42) 10-element Array{Float64,1}: 42.0 42.0 42.0 42.0 42.0 42.0 42.0 42.0 42.0 42.0
让我们“将一系列谬误更改为真”:
julia> trueArray = falses(3,3) 3x3 BitArray{2}: false false false false false false false false false
julia> fill!(trueArray, true) 3x3 BitArray{2}: true true true true true true true true true
julia> trueArray 3x3 BitArray{2}: true true true true true true true true true
你可以使用 range()
函数来创建类似向量的数组,接下来用 reshape()
把它们变为二维数组:
julia> a = reshape(range(0, stop=100, length=30), 10, 3) 10×3 reshape(::StepRangeLen{Float64,Base.TwicePrecision{Float64},Base.TwicePrecision{Float64}}, 10, 3) with eltype Float64: 0.0 34.4828 68.9655 3.44828 37.931 72.4138 6.89655 41.3793 75.8621 10.3448 44.8276 79.3103 13.7931 48.2759 82.7586 17.2414 51.7241 86.2069 20.6897 55.1724 89.6552 24.1379 58.6207 93.1034 27.5862 62.069 96.5517 31.0345 65.5172 100.0
结果是一个10乘3的阵列,包含0和100之间的等间距数字。
重复元素以填充数组
[编辑]repeat()
是通过重复较小的数组来创建数组的函数。
其语法的第一个选项是 repeat(A, n, m)
,源数组在第一维(行)中重复n次,在第二维(列)中重复m次。
您不必提供第二个维度,只需提供所需的行数:
julia> repeat([1, 2, 3], 2) 6-element Array{Int64,1}: 1 2 3 1 2 3 julia> repeat([1 2 3], 2) 2x3 Array{Int64,2}: 1 2 3 1 2 3
第二个选项表示额外的列:
julia> repeat([1, 2, 3], 2, 3) 6x3 Array{Int64,2}: 1 1 1 2 2 2 3 3 3 1 1 1 2 2 2 3 3 3 julia> repeat([1 2 3], 2, 3) 2x9 Array{Int64,2}: 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3
repeat()
函数还允许您通过复制源数组的行和列来创建数组。“内部”和“外部”选项确定是否重复行和/或列。例如,INNER=[2,3]生成一个数组,其中每行有两个副本,每列有三个副本:
inner
和 outer
选项 决定是否重复行 和/或 列。例如, inner = [2, 3]
生成一个数组,其中行拷贝两份,列拷贝三分:
julia> repeat([1, 2], inner = [2, 3]) 4x3 Array{Int64,2}: 1 1 1 1 1 1 2 2 2 2 2 2
相比之下, 这里 outer = [2,3]
:
julia> repeat([1, 2], outer = [2, 3]) 4x3 Array{Int64,2}: 1 1 1 2 2 2 1 1 1 2 2 2
注意后者等同于 repeat([1, 2], 2, 3)
。 outer
关键字的一个更有意义的示例是当它与 inner
关键字组合时。
此时,初始矩阵的每一行的每个元素都是行重复的,然后,生成的矩阵的每一行切片都是三列重复的:
julia> repeat([1 2; 3 4], inner=(2, 1), outer=(1, 3)) 4×6 Array{Int64,2}: 1 2 1 2 1 2 1 2 1 2 1 2 3 4 3 4 3 4 3 4 3 4 3 4
Array 构造器
[编辑]我们在前面看到过为您构建特定类型的数组:Array()
:
julia> Array{Int64}(undef, 6) 6-element Array{Int64,1}: 4454517776 4454517808 4454517840 4454517872 4454943824 4455998977
这是未初始化的;看起来奇怪的数字只是分配给新数组之前内存的旧内容。
嵌套数组
[编辑]创建嵌套数组很简单。有时我们要指定一下初始内容:
julia> a = Array[[1, 2], [3,4]] 2-element Array{Array,1}: [1, 2] [3, 4]
Array
构造器 也可以构建 数组的数组:
julia> Array[1:3, 4:6] 2-element Array{Array,1}: [1,2,3] [4,5,6]
您当然可以通过 reshape()
函数只创建一个简单的数组,然后更改其形状:
julia> reshape([1, 2, 3, 4, 5, 6, 7, 8], 2, 4) 2x4 Array{Int64,2}: 1 3 5 7 2 4 6 8
同样的技术也可用于创建三维阵列。下面是一个三维字符串数组:
julia> Array{String}(undef, 2, 3, 4) 2x3x4 Array{String,3}: [:, :, 1] = #undef #undef #undef #undef #undef #undef
[:, :, 2] = #undef #undef #undef #undef #undef #undef
[:, :, 3] = #undef #undef #undef #undef #undef #undef
[:, :, 4] = #undef #undef #undef #undef #undef #undef
每个元素都被设置为 '未定义' — #undef
.
push!()
函数将另一项推送到数组的最后:
julia> push!(a, rand(1:100, 5)) 3-element Array{Array,1}: [1, 2] [3, 4] [4, 71, 82, 60, 48] julia> push!(a, rand(1:100, 5)) 4-element Array{Array,1}: [1,2] [3,4] [4, 71, 82, 60, 48] [4, 22, 52, 5, 14]
或者你想创建一个空的数组:
julia> a = Array{Int}[] 0-element Array{Array{Int64,N} where N,1} julia> push!(a, [1, 2, 3]) 1-element Array{Array{Int64,N} where N,1}: [1, 2, 3] julia> push!(a, [4, 5, 6]) 2-element Array{Array{Int64,N} where N,1}: [1, 2, 3] [4, 5, 6]
你可以用 Vector
作为 Array
的别名:
julia> a = Vector{Int}[[1, 2], [3, 4]] 2-element Array{Array{Int64,1},1}: [1, 2] [3, 4] julia> push!(a, rand(1:100, 5)) 3-element Array{Array{Int64, 1},1}: [1, 2] [3, 4] [12, 65, 53, 1, 82] julia> a[2] 2-element Array{Int64,1}: 3 4 julia> a[2][1] 3
复制数组
[编辑]如果您有一个现有的数组,并且希望创建另一个具有相同维数的数组,则可以使用 similar()
函数:
julia> a = collect(1:10); # hide the output with the semicolon
julia> b = similar(a) 10-element Array{Int64,1}: 4482975872 4482975792 1 4482975952 4482976032 4482976112 3 3 2 4520636161
请注意,数组维度是被复制了,但是值没有被复制,它们是从随机的内存中复制的。
不过,您仍然可以更改类型和尺寸,因此它们不必如此相似:
julia> c = similar(b, String, (2, 2)) 2x2 Array{String,2}: #undef #undef #undef #undef
在任何情况下都有一个 copy()
函数。
矩阵操作:把数组作为矩阵来用
[编辑]在Julia中,二维数组可以用作矩阵。(如果维数和内容允许的话)所有可用于处理数组的函数都可以用作矩阵。
键入矩阵的一种快速方法是使用空格(生成行)分隔元素,并使用分号分隔行。所以:
θ
你也可以这样做:
julia> id = reshape([1, 2, 3, 4], 2, 2) 2×2 Array{Int64,2}: 1 3 2 4
它接受一个标准数组并对其调整形状,使其在两行和两列中运行。请注意,矩阵是逐列填充的。
如果你不使用逗号或分号:
julia> [1 2 3 4]
你将创建一个单行的数组/矩阵
1x4 Array{Int64,2}: 1 2 3 4
在每种情况下,请注意在类型值后面的大括号 ({Int64,2}
) 中的2。这表示二维数组。
可以通过相邻粘贴两个数组来创建数组,如下所示:
julia> [[1, 2, 3], [4, 5, 6]] 2-element Array{Array{Int64,1},1}: [1, 2, 3] [4, 5, 6]
当您省略逗号时,您将在每个列旁边放置列,您将得到以下结果:
julia> [[1, 2, 3] [4, 5, 6]] 3×2 Array{Int64,2}: 1 4 2 5 3 6
访问数组的内容
[编辑]若要访问数组或矩阵的元素,请在数组名称后加上方括号中的元素编号。以下是一维数组:
julia> a = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
这是第五个元素:
julia> a[5] 50
第一个元素索引号为1。Julia是从 1 而不是 0 开始对列表和数组中的元素进行索引的语言之一。
(因此,它属于 Matlab、Mathematica、Fortran、Lua 和 Smalltalk 等精英公司,而其他大多数编程语言则坚定地站在基于 0 的索引器的对立面。【译者注:应该是基于1的索引器的对立面?下为原文:】)
(And thus it's in the elite company of Matlab, Mathematica, Fortran, Lua, and Smalltalk, while most of the other programming languages are firmly in the opposite camp of 0-based indexers.)
最后一个元素称为 end (而不是像在其他一些语言中的-1):
julia> a[end] 100
类似地,您可以通过以下方式访问倒数第二个元素
julia> a[end-1] 90
(倒数第三个元素类似,依此类推)。
您可以提供一组索引号,这些索引号分别放在两端的一对括号中:
julia> a[[3,6,2]] 3-element Array{Int64,1}: 30 60 20
或提供一个范围的索引编号:
julia> a[2:2:end] 5-element Array{Int64,1}: 20 40 60 80 100
You can even select elements using true
and false
values:
甚至可以使用true
和 false
值来选择元素:
julia> a[[true, true, false, true, true, true, false, true, false, false]] 6-element Array{Int64,1}: 10 20 40 50 60 80
下面是一个2D数组,其中的行由分号分隔:
julia> a2 = [1 2 3; 4 5 6; 7 8 9] 3x3 Array{Int64,2}: 1 2 3 4 5 6 7 8 9 julia> a2[1] 1
如果您只要求2D数组的一个元素,您将得到一个值,就好像该数组是一列地展开的,即先向下,然后交叉。在这种情况下,您将得到4,而不是2:
julia> a2[2] 4
如您所想的请求行,然后列:
julia> a2[1, 2] 2
即行1,列2。下面是第 1 行第 3 列:
julia> a2[1, 3] 3
但是不要以错误的方式获取行/列索引:
julia> a2[1, 4] ERROR: BoundsError: attempt to access 3×3 Array{Int64,2} at index [1, 4] Stacktrace: [1] getindex(::Array{Int64,2}, ::Int64, ::Int64) at ./array.jl:498
顺便说一下,有一种从数组获取元素的替代方法:getindex()
函数:
julia> getindex(a2, 1, 3) 3 julia> getindex(a2, 1, 4) ERROR: BoundsError: attempt to access 3×3 Array{Int64,2} at index [1, 4] Stacktrace: [1] getindex(::Array{Int64,2}, ::Int64, ::Int64) at ./array.jl:498
使用冒号表示每行或每列。例如,下面是“每行第二列”:
julia> a2[:, 2] 3-element Array{Int64,1}: 2 5 8
下面是“第二行,每列”:
julia> a2[2, :] 3-element Array{Int64,1}: 4 5 6
元素级操作和向量化操作
[编辑]许多Julia函数和运算符专为处理数组而设计。这意味着您不必总是对一个数组单独处理每个元素。
一个简单的例子是使用基本的算术运算符。如果其他参数为单一值,则可以直接在数组中使用这些参数:
julia> a = collect(1:10); julia> a * 2 10-element Array{Int64,1}: 2 4 6 8 10 12 14 16 18 20
新数组的每个元素都是原来的乘以2。同样:
julia> a / 100 10-element Array{Float64,1}: 0.01 0.02 0.03 0.04 0.05 0.06 0.07 0.08 0.09 0.1
新数组的每个元素都是原来的除以100。
这些操作被描述为元素操作。
可以在许多运算符的前面加上一个点(.
). 这些与它们的无点版本相同,按元素处理数组元素。
例如,可以使用 .*
来使用乘法函数(*
)。这使您可以将数组或范围按元素相乘:
julia> n1 = 1:6; julia> n2 = 100:100:600; julia> n1 .* n2 6-element Array{Int64,1}: 100 400 900 1600 2500 3600
结果的第一个元素是通过将两个数组的第一个元素相乘得到的结果,以此类推。
除了算术运算符,一些比较运算符也有元素操作的版本。
例如,在循环中使用 .==
来比较两个数组,而不是使用 ==
。
下面是两个由 10 个数字组成的数组,一个是连续的,另一个是无序的,并且进行了元素比较,以查看数组 b 中有多少个元素与数组 a 恰好位于同一位置:
julia> a = 1:10; b=rand(1:10, 10); a .== b 10-element BitArray{1}: true false true false false false false false false false
Broadcasting: dot syntax for vectorizing functions
[编辑]这种使用点的语法将函数元素应用于数组的技术称为 广播。
在函数名后面,开括号前面加一个点,并提供一个数组或范围作为参数。
例如,下面是一个简单的函数,它将两个数字相乘:
julia> f(a, b) = a * b f (generic function with 1 method)
它在两个标量上按预期工作:
julia> f(2, 3) 6
但是,将此函数应用于数组是很容易的。只需使用点语法:
julia> f.([1, 4, 2, 8, 7], 10) 5-element Array{Int64,1}: 10 40 20 80 70
julia> f.(100, 1:10) 10-element Array{Int64,1}: 100 200 300 400 500 600 700 800 900 1000
在第一个示例中,Julia 自动将第二个参数视为数组,保证乘法操作正确。
min() 和 max()
[编辑]注意 max()
和 min()
. 你可能会觉得 max()
可以在数组上使用,就像这样,查找一个最大的元素:
julia> r = rand(0:10, 10) 10-element Array{Int64,1}: 3 8 4 3 2 5 7 3 10 10
但是,不行……
julia> max(r) LoadError: MethodError: no method matching max(::Array{Int64,1}) ...
max
函数返回其参数中最大的一个。要查找数组中最大的元素,可以使用相关函数maximum()
:
julia> maximum(r) 10
可以对两个或更多个数组使用 max()
执行元素检查,返回另一个包含最大值的数组:
julia> r = rand(0:10, 10); s = rand(0:10, 10); t = rand(0:10,10);
julia> max(r, s, t) 10-element Array{Int64,1}: 8 9 7 5 8 9 6 10 9 9
min()
和 minimum()
的行为方式类似。
使最大值适用于数组的一种方法是使用省略号(splat)运算符:
julia> max(r...) 9
可以使用按元素排列的运算符测试数组的每个值,并在单个操作中对其进行更改。下面是一个从0到10的随机整数组:
julia> a = rand(0:10,10, 10) 10x10 Array{Int64,2}: 10 5 3 4 7 9 5 8 10 2 6 10 3 4 6 1 2 2 5 10 7 0 3 4 1 10 7 7 0 2 4 9 5 2 4 2 1 6 1 9 0 0 6 4 1 4 8 10 1 4 10 4 0 5 1 0 4 4 9 2 9 4 10 9 6 9 4 5 1 1 1 9 10 10 1 9 3 2 3 10 4 6 3 2 7 7 5 4 6 8 3 8 0 7 1 0 1 9 7 5
现在可以测试每个值是否等于0,然后仅将这些元素设置为 11,如下所示:
julia> a[a .== 0] .= 11;
julia> a 10x10 Array{Int64,2}: 10 5 3 4 7 9 5 8 10 2 6 10 3 4 6 1 2 2 5 10 7 11 3 4 1 10 7 7 11 2 4 9 5 2 4 2 1 6 1 9 11 11 6 4 1 4 8 10 1 4 10 4 11 5 1 11 4 4 9 2 9 4 10 9 6 9 4 5 1 1 1 9 10 10 1 9 3 2 3 10 4 6 3 2 7 7 5 4 6 8 3 8 11 7 1 11 1 9 7 5
这是因为 a .== 0
返回一个包含 true
和 false
值的数组,然后使用这些值选择要设置为 11 的 a 的元素。
如果您正在对二维矩阵进行计算,您可能需要阅读更多关于矩阵算术的内容: Matrix arithmetic
行与列
[编辑]对于二维数组,可以使用括号、冒号和逗号提取单个行和列或行和列的范围。
对此 table :
julia> table = [r * c for r in 1:5, c in 1:5] 5x5 Array{Int64,2}: 1 2 3 4 5 2 4 6 8 10 3 6 9 12 15 4 8 12 16 20 5 10 15 20 25
您可以使用以下命令找到一行(请注意逗号):
julia> table[1, :] 1x5 Array{Int64,2}: 5-element Array{Int64,1}: 1 2 3 4 5
您可以得到一个范围内的行,其后跟一个逗号和一个冒号:
julia> table[2:3,:] 2x5 Array{Int64,2}: 2 4 6 8 10 3 6 9 12 15
要选择列,请以冒号开头,后跟逗号:
julia> table[:, 2] 5-element Array{Int64,1}: 2 4 6 8 10
冒号本身访问整个数组:
julia> table[:] 25-element Array{Int64,1}: 1 2 3 4 5 2 4 6 8 10 3 6 9 12 15 4 8 12 16 20 5 10 15 20 25
要提取列范围,请执行以下操作:
julia> table[:, 2:3] 5x2 Array{Int64,2}: 2 3 4 6 6 9 8 12 10 15
数组中查找元素
[编辑]如果您想知道数组是否包含项,请使用 in()
函数,可以通过两种方式调用该函数:
julia> a = 1:10
julia> 3 in a true
或者作为函数调用:
julia> in(3, a) # needle ... haystack true
有一组以 find 开头的函数,例如 findall()
, findfirst()
, findnext()
, findprev()
和 findlast()
,您可以使用这些函数来获取匹配特定值的数组单元格的索引,或者传入一个判断。其中每一种都有两种或两种以上的形式。
下面是一组小素数:
julia> smallprimes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29];
要查找数字的第一个匹配项并获取其索引,可以使用 findfirst()
函数的以下方法:
julia> findfirst(isequal(13), smallprimes) 6
因此,数组中的第一个 13 出现在第六个单元格中:
julia> smallprimes[6] 13
该函数类似于Julia中的许多函数,接受一个函数作为第一个参数。该函数应用于数组的每个元素,如果函数返回true,则返回该元素或其索引。
该函数返回第一个元素的索引。
下面是另一个使用匿名函数的示例:
julia> findfirst(x -> x == 13, smallprimes) 6
findall()
函数返回索引数组,指向应用时函数返回true的每个元素:
julia> findall(isinteger, smallprimes) 10-element Array{Int64,1}: 1 2 3 4 5 6 7 8 9 10
julia> findall(iseven, smallprimes) 1-element Array{Int64,1}: 1
请记住,这些是索引号的数组,而不是实际的单元格值。索引可用于使用标准的方括号语法提取相应的值:
julia> smallprimes[findall(isodd, smallprimes)] 9-element Array{Int64,1}: 3 5 7 11 13 17 19 23 29
鉴于 findfirst()
返回一个数字,即第一个匹配单元格的索引:
julia> findfirst(iseven, smallprimes) 1
julia> smallprimes[findfirst(iseven, smallprimes)] 2
findnext()
函数与 findall()
和 findfirst()
函数非常相似,但它接受一个额外的数字,告诉函数从数组中间的某个位置开始搜索,而不是从头开始。
例如,如果 findfirst(smallprimes,13)
查找数组中数字 13 第一次出现的索引,则可以在findnext()
中使用以下值从此处继续搜索:
julia> findnext(isodd, smallprimes, 1 + findfirst(isequal(13), smallprimes)) 7
julia> smallprimes[ans] 17
findin(A, B)
函数返回数组 A 中的元素可在数组 B 中找到的元素的索引:
julia> findall(in([11, 5]), smallprimes) 2-element Array{Int64,1}: 3 5 julia> smallprimes[3] 5 julia> smallprimes[5] 11
应该注意索引的返回顺序。
Finding out about an array
[编辑]对于二维数组:
julia> a2 = [1 2 3; 4 5 6; 7 8 9] 3x3 Array{Int64,2}: 1 2 3 4 5 6 7 8 9
我们可以使用以下函数了解有关它的更多信息:
ndims()
size()
length()
count()
ndims()
返回维数。向量为1,表为2,依此类推:
julia> ndims(a2) 2
size()
以元组的形式返回数组的行数和列数:
julia> size(a2) (3,3)
length()
告诉您数组包含多少元素:
julia> length(a2) 9
你可以使用 count()
来查找特定值出现的次数。例如,有多少个非零项?
julia> count(!iszero, a2) 9
要查找数组/矩阵的逆、行列式和其他方面,请参见 Manipulating matrices.。
要在索引号 (从 1 到 n
) 和 行/列号 (1:r
, 1:c
) 之间进行转换, 可以使用:
julia> CartesianIndices(a2)[6] CartesianIndex(3, 2)
例如,查找第六个元素的行和列。
在另一个方向上,什么索引号对应于第3行,第2列?
使用与笛卡尔索引相反的线性索引:
julia> LinearIndices(a2)[3, 2] 6
数组比较
[编辑]union()
构建一个新数组,该数组是两个或多个数组的联合或组合。该操作将删除重复项,并且结果包含每个元素的唯一版本:
julia> odds = collect(1:2:10) 5-element Array{Int64,1}: 1 3 5 7 9
julia> evens = collect(2:2:10) 5-element Array{Int64,1}: 2 4 6 8 10
julia> union(odds, evens) 10-element Array{Int64,1}: 1 3 5 7 9 2 4 6 8 10
请注意,新联合的顺序反映了原始顺序。此示例根本不对数字进行排序:
julia> union(1:5, 1:10, 5:-1:-5) 16-element Array{Int64,1}: 1 2 3 4 5 6 7 8 9 10 0 -1 -2 -3 -4 -5
intersect()
返回一个新数组,该数组是两个或多个数组的交集。结果包含每个元素的一个匹配项,但仅当它出现在每个数组中时:
julia> intersect(1:10, 5:15) 5:10
julia> intersect(5:20, 1:15, 3:12) 5:12
setdiff()
查找两个数组之间的不同,即 是第一个数组中的元素,而不是第二个数组中的元素:
julia> setdiff(1:15, 5:20) 4-element Array{Int64,1}: 1 2 3 4
julia> setdiff(5:20, 1:15) 5-element Array{Int64,1}: 16 17 18 19 20
过滤 filter
[编辑]有一组相关函数可以让您处理数组的元素。
filter()
在元素通过测试时查找并保留这些元素。在这里,我们使用 isodd()
函数 (将其作为不带括号的命名函数传递,而不是带括号的函数调用) 来过滤(保留)所有 数组中是奇数的项。
julia> filter(isodd, 1:10) 5-element Array{Int64,1}: 1 3 5 7 9
和许多 Julia 函数一样,有一个版本可以更改数组。因此 filter()
返回原始数据的副本,但 filter!()
改变了数组。
我们前面遇到的 count()
函数类似于 filter()
, 但只计算满足条件的元素数:
julia> count(isodd, 1:100) 50
另外,any()
函数只告诉您任何元素是否满足条件:
julia> any(isodd, 1:100) true
all()
函数告诉您是否所有元素都满足条件。在这里 all()
检查 filter()
是否正确地完成了这项工作。
julia> all(isodd, filter(isodd, 1:100)) true
随机元素
[编辑]要从阵列中选择随机元素,请执行以下操作:
julia> a = collect(1:100); julia> a[rand(1:end)] 14
其他函数
[编辑]数组是 Julia 的基础,这里无法具体描述几十个数组处理函数。但这里有几个选择:
找到数组中的极值:
julia> a = rand(100:110, 10) 10-element Array{Int64,1}: 109 102 104 108 103 110 100 108 101 101
julia> extrema(a) (100,110)
findmax()
查找最大元素并在元组中返回它及其索引:
julia> findmax(a) (110,6)
例如 sum()
, prod()
, mean()
, middle()
, 会执行你所期望的操作:
(mean()
和 middle()
已移到标准库的 Statistics 模块中,您可能需要首先输入 "using Statistics
" 才能使用它们)
julia> sum(a) 1046
julia> prod(1:10) 3628800
julia> mean(a) 104.6
julia> middle(a) 105.0
sum()
, mean()
, and prod()
还允许提供函数:将该函数应用于每个元素,然后对结果求和/平均值/积:
julia> sum(sqrt, 1:10) # the sum of the square roots of the first 10 integers 前10个整数的平方根之和 22.4682781862041 julia> mean(sqrt, 1:10) # the mean of the square roots of the first 10 integers 前十个证书的平方根的平均值 2.24682781862041
Combinatorics.jl 包中的函数允许您查找数组的组合和排列。 combinations()
查找数组中所有可能的元素组合:您可以指定每个组合中的元素数:
julia> Pkg.add("Combinatorics") # (do this just once) julia> using Combinatorics julia> collect(combinations(a, 3)) 120-element Array{Array{Int64,1},1}: [109,102,104] [109,102,108] [109,102,103] [109,102,110] [109,102,100] [109,102,108] [109,102,101] [109,102,101] [109,104,108] [109,104,103] [109,104,110] [109,104,100] [109,104,108] ⋮ [103,108,101] [103,101,101] [110,100,108] [110,100,101] [110,100,101] [110,108,101] [110,108,101] [110,101,101] [100,108,101] [100,108,101] [100,101,101] [108,101,101]
以及 permutations()
生成所有的排列。实际上,您可能不需要使用 collect()
将项收集到数组中:
julia> length(permutations(a)) 3628800
改变数组内容: 添加删除元素
[编辑]要在数组末尾添加项,请使用 push!()
:
julia> a = collect(1:10); push!(a, 20) 11-element Array{Int64,1}: 1 2 3 4 5 6 7 8 9 10 20
与往常一样,感叹号会提醒您此函数会更改数组。你只能将其 push 到向量的末端。
要在前面添加元素,请使用 pushfirst!()
:
julia> pushfirst!(a, 0) 12-element Array{Int64,1}: 0 1 2 3 4 5 6 7 8 9 10 20
若要在给定索引处将元素插入到数组中,请使用 splice!()
例如,下面是一个明显有遗漏的数字列表:
julia> a = [1, 2, 3, 5, 6, 7, 8, 9] 8-element Array{Int64,1}: 1 2 3 5 6 7 8 9
使用 splice!()
在特定的索引值范围内插入序列。Julia返回已替换的值。数组会增长以容纳新的元素,并且在序列插入之后,元素会被向下推。让我们在位置 4:5 的地方插入范围 4:6
:
julia> splice!(a, 4:5, 4:6) 2-element Array{Int64,1}: 5 6
您可能会尝试检查是否正确插入了新值:
julia> a 9-element Array{Int64,1}: 1 2 3 4 5 6 7 8 9
现在,如果要在特定的索引间位置插入一些值,则必须使用称为“空范围”的功能。在这种情况下,索引 n-1 和 n 之间的间隔表示为 n:n-1
。
例如:
julia> L = ['a','b','f'] 3-element Array{Char,1}: 'a' 'b' 'f'
julia> splice!(L, 3:2, ['c','d','e']) 0-element Array{Char,1}
julia> L 6-element Array{Char,1}: 'a' 'b' 'c' 'd' 'e' 'f'
删除元素
[编辑]如果不提供替换,也可以使用 splice!()
来删除元素并移动其余元素。
julia> a = collect(1:10); julia> splice!(a,5); julia> a 9-element Array{Int64,1}: 1 2 3 4 6 7 8 9 10
要删除最后一项,请执行以下操作:
julia> pop!(a) 10
删除第一项:
julia> popfirst!(a) 1
More aggressive modification of arrays (and similar data structures) can be made with functions such as deleteat!()
and splice!()
. You can find out the indices of elements in various ways. Once you know the indices, you can use deleteat!()
to delete an element, given its index number:
julia> a = collect(1:10);
julia> findfirst(isequal(6), a) 4
julia> deleteat!(a, findfirst(isequal(6), a)) 9-element Array{Int64,1}: 1 2 3 4 5 7 8 9 10
deleteat!()
also accepts a range or iterator to specify the indices, so you can do this:
julia> deleteat!(a, 2:6) 4-element Array{Int64,1}: 1 8 9 10
Remember that you can always remove a group of elements using a filter: see Filtering.
其他函数
[编辑]If you want to do something to an array, there's probably a function to do it, and sometimes with an exclamation mark to remind you of the potential consequences. Here are a few more of these array-modifying functions:
resize!()
change the length of a Vectorappend!()
push a second collection at the back of the first oneprepend!()
insert elements at the beginning of the first Vectorempty!(a)
remove all elementsrotr90(a)
make a copy of an array rotated 90 degrees clockwise:
julia> rotr90([1 2 3 ; 4 5 6]) 3x2 Array{Int64,2}: 4 1 5 2 6 3
circshift(a)
move the elements around 'in a circle' by a number of steps:
julia> circshift(1:6, 1) 6-element Array{Int64,1}: 6 1 2 3 4 5
This function can also do circular shifts on 2D arrays too. For example, here's a table:
julia> table = collect(r*c for r in 1:5, c in 1:5) 5×5 Array{Int64,2}: 1 2 3 4 5 2 4 6 8 10 3 6 9 12 15 4 8 12 16 20 5 10 15 20 25
By supplying a tuple you can move rows and columns. For example: moving the columns by 0 and the rows by 1 moves the first dimension by 0 and the second by 1. The first dimension is downwards, the second rightwards:
julia> circshift(table, (0, 1)) 5×5 Array{Int64,2}: 5 1 2 3 4 10 2 4 6 8 15 3 6 9 12 20 4 8 12 16 25 5 10 15 20
There's a modifying version of circshift()
, circshift!
设置数组内容
[编辑]To set the contents of an array, specify the indices on the left-hand side of an assignment expression:
julia> a = collect(1:10); julia> a[9]= -9 -9
To check that the array has really changed:
julia> print(a) [1,2,3,4,5,6,7,8,-9,10]
You can set a bunch of elements at the same time, using the broadcasting assignment operator:
julia> a[3:6] .= -5 4-element view(::Array{Int64,1}, 3:6) with eltype Int64: -5 -5 -5 -5 julia> print(a) [1,2,-5,-5,-5,-5,7,8,-9,10]
And you can set a sequence of elements to a suitable sequence of values:
julia> a[3:9] = collect(9:-1:3) 7-element Array{Int64,1}: 9 8 7 6 5 4 3
Notice here that, although Julia shows the 7 element slice as the return value, in fact the whole array has been modified:
julia> a 10-element Array{Int64,1}: 1 2 9 8 7 6 5 4 3 10
You can set ranges to a single value in one operation using broadcasting:
julia> a[1:5] .= 0 0
julia> a 10-element Array{Int64,1}: 0 0 0 0 0 6 7 8 9 10
julia> a[1:10] .= -1; -1
julia> print(a) [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1]
As an alternative to the square bracket notation, there's a function call version that does the same job of setting array contents, setindex!()
:
julia> setindex!(a, 1:10, 10:-1:1) 10-element Array{Int64,1}: 10 9 8 7 6 5 4 3 2 1
You can refer to the entire contents of an array using the colon separator without start and end index numbers, i.e. [:]
. For example, after creating the array a
:
julia> a = collect(1:10);
we can refer to the contents of this array a
using a[:]
:
julia> b = a[:] 10-element Array{Int64,1}: 1 2 3 4 5 6 7 8 9 10 julia> b[3:6] 4-element Array{Int64,1}: 3 4 5 6
把数组传递给函数
[编辑]函数不能够改变传递进来的参数的值,但是可以对传递进来的 容器 的内容进行修改。
请考虑以下函数,该函数将其参数更改为5:
julia> function set_to_5(x) x = 5 end set_to_5 (generic function with 1 method)
julia> x = 3 3
julia> set_to_5(x) 5
julia> x 3
尽管函数里面的 x
被改变了 ,函数外面的 x
也没有变。函数里面的变量名是局部的。
但是,你可以改变一个容器的内容,比如数组。下面一个函数使用 语法来获取 容器 x
的内容,而不是直接改变 变量x
的值。
julia> function fill_with_5(x) x[:] .= 5 end fill_with_5 (generic function with 1 method)
julia> x = collect(1:10) 10-element Array{Int64,1}: 1 2 3 4 5 6 7 8 9 10
julia> fill_with_5(x) 5
julia> x 10-element Array{Int64,1}: 5 5 5 5 5 5 5 5 5 5
If, instead of accessing the container variable's contents, you try to change the variable itself, it won't work. For example, the following function definition creates an array of 5s in temp
and then attempts to change the argument x
to be temp
.
julia> function fail_to_fill_with_5(x) temp = similar(x) for i in 1:length(x) temp[i] = 5 end x = temp end fail_to_fill_with_5 (generic function with 1 method)
julia> x = collect(1:10) 10-element Array{Int64,1}: 1 2 3 4 5 6 7 8 9 10
julia> fail_to_fill_with_5(x) 10-element Array{Int64,1}: 5 5 5 5 5 5 5 5 5 5
It looks like it worked, but:
julia> x 10-element Array{Int64,1}: 1 2 3 4 5 6 7 8 9 10
You can change elements of the array, but you can't change the variable so that it points to a different array. In other words, your function isn't allowed to change the binding between the argument and the array that was passed to it.
Julia's way of handling function arguments is described as “pass-by-sharing”. An array isn't copied when you pass it to a function (that would be very inefficient for large arrays).
矩阵运算
[编辑]For matrix-on-matrix arithmetic action, you can:
- add (+) and subtract (-):
θ
θ
θ
θ
- multiply (*), assuming the dimensions are compatible, so m1 * m2
is possible if last(size(m1)) == first(size(m2))
. Note the difference between matrix multiplication and elementwise matrix multiplication. Here's a matrix A
:
θ
and here's matrix B
:
θ
The .*
broadcasting operator multiplies them elementwise:
θ
Compare this with matrix multiplication, A * B
:
θ
which is:
julia> [1 * 10 + 2 * 12 1 * 11 + 2 * 13 ; 3 * 10 + 4 * 12 3 * 11 + 4 * 13] 2x2 Array{Int64,2}: 34 37 78 85
- division of two matrices. You can use the backslash (\) for left division:
julia> A = rand(1:9, 3, 3) 3x3 Array{Int64,2}: 5 4 3 8 7 7 9 3 7
julia> B = rand(1:9, 3, 3) 3x3 Array{Int64,2}: 6 5 5 6 7 5 7 2 7
julia> A \ B 3x3 Array{Float64,2}: 2.01961 0.411765 1.84314 0.254902 1.35294 -0.0392157 -1.70588 -0.823529 -1.35294
and the forward slash (/) right or slash division:
julia> A / B 3x3 Array{Float64,2}: 4.0 -2.0 -1.0 0.285714 0.714286 0.285714 5.07143 -3.07143 -0.428571
With a matrix and a scalar, you can add, subtract, multiply, and divide:
julia> A + 1 3x3 Array{Int64,2}: 6 5 4 9 8 8 10 4 8
julia> [1 2 3 4 5] * 2 1x5 Array{Int64,2}: 2 4 6 8 10
julia> A .- 1 3x3 Array{Int64,2}: 4 3 2 7 6 6 8 2 6
julia> A .* 2 3x3 Array{Int64,2}: 10 8 6 16 14 14 18 6 14
julia> A ./ 2 3x3 Array{Float64,2}: 2.5 2.0 1.5 4.0 3.5 3.5 4.5 1.5 3.5
and more besides:
julia> A // 2 3x4 Array{Rational{Int64},2}: 1//2 2//1 7//2 5//1 1//1 5//2 4//1 11//2 3//2 3//1 9//2 6//1
julia> A .< 6 3x3 BitArray{2}: true true true false false false false true false
You can multiply matrix and a vector (the matrix-vector product), if the arrays have compatible shapes. Here's the matrix A:
θ
and here's a vector V:
θ
The *
operator multiplies them:
θ
The dot or inner product (aTb) can be found using the dot()
function, but you'll have to import the LinearAlgebra library first:
julia> using LinearAlgebra
θ
julia> (1 * 21) + (2 * 22) + (3 * 23) 134
The two arguments must have the same length. You can also use the dot operator, which you can obtain in the REPL by typing "\cdot" followed by a tab:
julia> [1:3] ⋅ [21:23] 134
连接数组和矩阵
[编辑]You can use hcat()
and vcat()
to join matrices together, if their dimensions permit.
hcat()
keeps the first dimension and extends (joins) in the second, vcat()
keeps the second dimension and extends the first.
Here are two 3 by 4 matrices:
julia> A = reshape(1:12, 3, 4) 3x4 Array{Int64,2}: 1 4 7 10 2 5 8 11 3 6 9 12
julia> B = reshape(100:100:1200, 3, 4) 3x4 Array{Int64,2}: 100 400 700 1000 200 500 800 1100 300 600 900 1200
hcat(A, B)
makes a new array that still has 3 rows, but extends/joins the columns to make 8 in total:
julia> hcat(A, B) 3x8 Array{Int64,2}: 1 4 7 10 100 400 700 1000 2 5 8 11 200 500 800 1100 3 6 9 12 300 600 900 1200
vcat(A, B)
makes a new array that keeps the 4 columns, but extends to 6 rows:
julia> vcat(A, B) 6x4 Array{Int64,2}: 1 4 7 10 2 5 8 11 3 6 9 12 100 400 700 1000 200 500 800 1100 300 600 900 1200
You'll probably find the shortcuts useful:
- [A ; B ] is
vcat(A, B)
- [A B ] is
hcat(A, B)
vec()
flattens a matrix into a vector, turning it into a (what some call a 'column') vector:
julia> vec(ones(3, 4)) 12-element Array{Float64,1}: 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
There's also an hvcat()
function ([A B; C D;]
) that does both.
You can use hcat()
to convert an array of arrays to a matrix (using the hcat-splat):
julia> a = Array[[1, 2], [3, 4], [5, 6]] 3-element Array{Array{T,N},1}: [1, 2] [3, 4] [5, 6] julia> hcat(a...) 2x3 Array{Int64,2}: 1 3 5 2 4 6
Julia arrays are 'column-major'. This means that you read down the columns:
1 3 2 4
whereas 'row-major' arrays are to be read across, like this:
1 2 3 4
Column-major order is used in Fortran, R, Matlab, GNU Octave, and by the BLAS and LAPACK engines (the "bread and butter of high-performance numerical computation"). Row-major order is used in C/C++, Mathematica, Pascal, Python, C#/CLI/.Net and others.
增广和扩展数组
[编辑]Often you want to create an array and then add more to it, or 'grow' it. While can do this with vcat()
and hcat()
, be aware that both these operations create new temporary arrays and copy elements, so they don't always produce the fastest code. A better way is to use push!
. This is an efficient operation that extends the array. You can reshape the array later:
julia> a = [] julia> for i = 1:80 push!(a, i) end julia> a 80-element Array{Any,1}: 1 2 3 4 5 6 7 8 9 ⋮ 75 76 77 78 79 80
reshape()
lets you change the dimensions of an array. You can supply the dimensions or use a colon (:
) to ask Julia to calculate valid dimensions:
julia> reshape(a, 10, :) 10x8 Array{Any,2}: 1 11 21 31 41 51 61 71 2 12 22 32 42 52 62 72 3 13 23 33 43 53 63 73 4 14 24 34 44 54 64 74 5 15 25 35 45 55 65 75 6 16 26 36 46 56 66 76 7 17 27 37 47 57 67 77 8 18 28 38 48 58 68 78 9 19 29 39 49 59 69 79 10 20 30 40 50 60 70 80
reshape(a, (10, div(length(a), 10)))
would have the same effect.
push!()
doesn't let you push new rows to a 2D array or matrix. The best way to do the job is to work on a 1D array, as above, adding more elements at the end, and then use reshape()
to convert it to two dimensions. If necessary, use transpose()
to flip the matrix.
操作矩阵
[编辑]To transpose an array or matrix, there's an equivalent '
operator for the transpose()
function, to swap rows and columns:
julia> M = reshape(1:12, 3, 4) 3×4 Base.ReshapedArray{Int64,2,UnitRange{Int64},Tuple{}}: 1 4 7 10 2 5 8 11 3 6 9 12
julia> transpose(M) 4x3 Array{Int64,2}: 1 2 3 4 5 6 7 8 9 10 11 12
julia> M' 4x3 Array{Int64,2}: 1 2 3 4 5 6 7 8 9 10 11 12
To find the determinant of a square matrix, use det()
, after remembering to load the LinearAlgebra library.
julia> using LinearAlgebra julia> A = rand(2:10, 3, 3) 3x3 Array{Int64,2}: 8 8 2 6 9 6 9 2 10
julia> det(A) 438.00000000000006
inv()
(in the Standard Library) finds the inverse of a square matrix, if it has one. (If the determinant of the matrix is zero, it won't have an inverse.)
julia> inv(A) 3x3 Array{Float64,2}: 0.178082 -0.173516 0.0684932 -0.0136986 0.141553 -0.0821918 -0.157534 0.127854 0.0547945
LinearAlgebra.rank()
finds the rank of the matrix, and LinearAlgebra.nullspace()
finds the basis for the nullspace.
julia> A 3x4 Array{Int64,2}: 1 4 7 10 2 5 8 11 3 6 9 12
julia> rank(A) 2
julia> nullspace(A) 4x2 Array{Float64,2}: -0.475185 -0.272395 0.430549 0.717376 0.564458 -0.617566 -0.519821 0.172585
LinearAlgebra.tr()
sums the diagonal of a square matrix (trace):
julia> s = reshape(1:9, 3, 3) 3x3 Array{Int64,2}: 1 4 7 2 5 8 3 6 9
julia> tr(s) 15
对矩阵调用函数
[编辑]There are a number of functions that can be applied to a matrix:
- sum()
adds every element:
julia> A = reshape(1:9, 3, 3) 3×3 Base.ReshapedArray{Int64,2,UnitRange{Int64},Tuple{}}: 1 4 7 2 5 8 3 6 9
julia> sum(A) 45
You can specify a dimension if you want to sum just columns or rows. So to sum columns, specify dimension 1:
julia> sum(A, dims=(1)) 1x3 Array{Int64,2}: 6 15 24
To sum rows, specify dimension 2:
julia> sum(A, dims=(2)) 3x1 Array{Int64,2}: 12 15 18
- mean()
finds the mean of the values in the matrix:
julia> using Statistics; mean(A) 5.0
As with sum()
, you can specify a dimension, so that you can find the mean of columns (use dimension 1) or rows (use dimension 2):
julia> mean(A, dims=(1)) 1x3 Array{Float64,2}: 2.0 5.0 8.0
julia> mean(A, dims=(2)) 3x1 Array{Float64,2}: 4.0 5.0 6.0
- the min(A, B)
and max(A, B)
functions compare two (or more) arrays element by element, returning a new array with the largest (or smallest) values from each:
julia> A = rand(-1:2:1, 3, 3) 3x3 Array{Int64,2}: -1 -1 -1 -1 1 1 1 -1 1
julia> B = rand(-2:4:2, 3, 3) 3x3 Array{Int64,2}: 2 2 2 2 -2 2 2 2 2
prod()
multiplies a matrix's elements together:
julia> A = reshape(collect(BigInt(1):25), 5, 5) 5×5 Array{BigInt,2}: 1 6 11 16 21 2 7 12 17 22 3 8 13 18 23 4 9 14 19 24 5 10 15 20 25 julia> prod(A) 15511210043330985984000000
(Notice the use of BigInt
, products are very large.)
You can specify a dimension if you want to multiply just columns or rows. To multiply the elements of columns together, specify dimension 1; for rows, use dimension 2:
julia> prod(A, 1) 1x5 Array{Int64,2}: 120 30240 360360 1860480 6375600
julia> prod(A, 2) 5x1 Array{Int64,2}: 22176 62832 129168 229824 375000
矩阵范数
[编辑]大多数矩阵的函数在 LinearAlgebra 库中:
julia> using LinearAlgebra
向量范数
[编辑]向量的欧几里得范数, , 在 LinearAlgebra.norm(x)
:
julia> X = [2, 4, -5] 3-element Array{Int64,1}: 2 4 -5 julia> LinearAlgebra.norm(X) # Euclidean norm 6.708203932499369 julia> LinearAlgebra.norm(x, 1) # 1-norm of the vector, the sum of element magnitudes 11.0
如果 X 是一个 '行' 向量:
julia> X = [2 4 -5] 1x3 Array{Int64,2}: 2 4 -5 julia> LinearAlgebra.norm(X) 6.708203932499369 julia> LinearAlgebra.norm(X, 1) 5.0
对于向量 和 向量 之间的欧几里得距离 , is found by norm(x - y)
:
julia> LinearAlgebra.norm([1 2 3] - [2 4 6]) 3.741657386773941 julia> LinearAlgebra.norm([1, 2, 3] - [2, 4, 6]) 3.741657386773941
The angle between two vectors and is :
acos(dot(a,b)/(norm(a)*norm(b)))
矩阵范数
[编辑]Here's the 1-norm of a matrix (the maximum absolute column sum):
julia> B = [5 -4 2 ; -1 2 3; -2 1 0] 3x3 Array{Int64,2}: 5 -4 2 -1 2 3 -2 1 0
julia> LinearAlgebra.norm(B, 1) 8.0
And here's the infinity norm (the maximum absolute row sum):
julia> LinearAlgebra.norm(B, Inf) 11.0
The Euclidean norm()
is the default:
julia> LinearAlgebra.norm([2 3 ; 4 6]), sqrt(2^2 + 3^2 + 4^2 + 6^2) (8.062257748298547,8.06225774829855)
Scaling and rotating matrices
[编辑]- rmul!(A, n)
scales every element of the matrix in place by a scale factor n
:
julia> A = [1 2 3 4 5 6 7 8 9] 3×3 Array{Int64,2}: 1 2 3 4 5 6 7 8 9 julia> rmul!(A, 2) 3×3 Array{Int64,2}: 2 4 6 8 10 12 14 16 18
There are rotation and circular-shifting functions too:
julia> A = [1 2 3 4 5 6 7 8 9] 3×3 Array{Int64,2}: 1 2 3 4 5 6 7 8 9
julia> rot180(A) 3×3 Array{Int64,2}: 9 8 7 6 5 4 3 2 1
julia> circshift(A, (1, 1)) 3×3 Array{Int64,2}: 9 7 8 3 1 2 6 4 5
julia> A 3×3 Array{Int64,2}: 1 2 3 4 5 6 7 8 9
reverse()
makes a copy of a matrix reversing rows or columns:
julia> reverse(A, dims=(1)) 3×3 Array{Int64,2}: 7 8 9 4 5 6 1 2 3
julia> reverse(A, dims=(2)) 3×3 Array{Int64,2}: 3 2 1 6 5 4 9 8 7
squeeze()
and reshape()
can be used to change the dimensions of a matrix. For example, this is how you can use squeeze()
to collapse a row vector (1 by 4) into a 4 by 1 array:
julia> a = [1 2 3 4] 1x4 Array{Int64,2}: 1 2 3 4
julia> ndims(a) 2
julia> b = squeeze(a, dims=(1)) 4-element Array{Int64,1}: 1 2 3 4
julia> ndims(b) 1
数组排序
[编辑]Julia has a flexible sort()
function that returns a sorted copy of an array, and a companion sort!()
version that changes the array so that it's sorted.
You can usually use sort()
without options and obtain the results you'd hoped for:
julia> using Random julia> rp = randperm(10) 10-element Array{Int64,1}: 6 4 7 3 10 5 8 1 9 2
julia> sort(rp) 10-element Array{Int64,1}: 1 2 3 4 5 6 7 8 9 10
You can sort 2D arrays:
julia> a = reshape(rand(1:20, 20), 4, 5) 4x5 Array{Int64,2}: 19 13 4 10 10 6 20 19 18 12 17 7 15 14 9 1 16 8 7 13
julia> sort(a, dims=(1)) # sort each column, dimension 1 4x5 Array{Int64,2}: 1 7 4 7 9 6 13 8 10 10 17 16 15 14 12 19 20 19 18 13
julia> sort(a, dims=(2)) # sort each row, dimension 2 4x5 Array{Int64,2}: 4 10 10 13 19 6 12 18 19 20 7 9 14 15 17 1 7 8 13 16
although there are more powerful alternatives in sortrows()
and sortcolumns()
— see below for details.
The sortperm()
function is similar to sort()
, but it doesn't return a sorted copy of the collection. Instead it returns a list of indices that could be applied to the collection to produce a sorted version:
julia> r = rand(100:110, 10) 10-element Array{Int64,1}: 103 102 110 108 108 108 104 109 106 106
julia> sortperm(r) 10-element Array{Int64,1}: 2 1 7 9 10 4 5 6 8 3
julia> r[sortperm(r)] 10-element Array{Int64,1}: 102 103 104 106 106 108 108 108 109 110
排序和比较
[编辑]If you need more than the default sort()
offers, use the by
and lt
keywords and provide your own functions for processing and comparing elements during the sort.
sort by
[编辑]The by
function processes each element before comparison and provides the 'key' for the sort. A typical example is the task of sorting a list of numbers in string form into numerical order. Here's the list:
julia> r = ["1E10", "150", "25", "3", "1.5", "1E-10", "0.5", ".999"];
If you use the default sort, the numbers appear in the order in which the characters appear in Unicode/ASCII:
julia> sort(r) 8-element Array{ASCIIString,1}: ".999" "0.5" "1.5" "150" "1E-10" "1E10" "25" "3"
with "1E-10" appearing after "0.999".
To sort the numbers by their value, pass the parse()
function (from the Meta package) to by
:
julia> sort(r, by = x -> Meta.parse(x)) 8-element Array{String,1}: "1E-10" "0.5" ".999" "1.5" "3" "25" "150" "1E10"
The strings are sorted 'by' their value. Notice that the by
function you supply produces the numerical sort key, but the original string elements appear in the final result.
Anonymous functions can be useful when sorting arrays. Here's a 10 rows by 2 columns array of tuples:
julia> table = collect(enumerate(rand(1:100, 10))) 10-element Array{(Int64,Int64),1}: (1,86) (2,25) (3,3) (4,97) (5,89) (6,58) (7,27) (8,93) (9,98) (10,12)
You can sort this array by the second element of each tuple, not the first, by supplying an anonymous function to by
that points to the second element of each. The anonymous function says, given an object x
to sort, sort by the second element of x
:
julia> sort(table, by = x -> x[2]) 10-element Array{(Int64,Int64),1}: (3,3) (10,12) (2,25) (7,27) (6,58) (1,86) (5,89) (8,93) (4,97) (9,98)
Sorting by multiple columns
[编辑]You can supply a tuple of "column" identifiers in the by
function, if you want to sort by more than one column.
julia> a = [[2, 2, 2, 1], [1, 1, 1, 8], [2, 1, 2, 2], [1, 2, 2, 5], [2, 1, 1, 4], [1, 1, 2, 7], [1, 2, 1, 6], [2, 2, 1, 3]] ;
julia> sort(a, by = col -> (col[1], col[2], col[3])) 8-element Array{Array{Int64,1},1}: [1,1,1,8] [1,1,2,7] [1,2,1,6] [1,2,2,5] [2,1,1,4] [2,1,2,2] [2,2,1,3] [2,2,2,1]
This sorts the array first by column 1, then by column 2, then by column 3.
Redefining 'less than'
[编辑]By default, sorting uses the built-in isless()
function when comparing elements. In a sorted array, the first element is less than the second.
You can change this behaviour by passing a different function to the lt
keyword. This function should compare two elements and return true if they're sorted, i.e. if the first element is 'less than' the second, using some definition of 'less than'. The sorting process compares pairs of elements repeatedly until every element of the array is in the right place.
For example, suppose you want to sort an array of words according to the number of vowels in each word; i.e. the more vowels a word has, the earlier in the sorted results it occurs. For example, the word "orange" will be considered to be "less than" the word "lemon", because it has more vowels.
First we'll need a function that counts vowels:
vowelcount(string) = count(c -> (c in "aeiou"), lowercase(string))
Now you can pass an anonymous function to sort()
that compares the vowel count of two elements using this function and then returns the element with a higher count in each case:
sentence = split("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.");
sort(sentence, lt = (x,y) -> vowelcount(x) > vowelcount(y))
The result is that the word with the most vowels appears first:
19-element Array{SubString{String},1}:
"adipisicing"
"consectetur"
"eiusmod"
"incididunt"
"aliqua."
"labore"
"dolore"
"Lorem"
"ipsum"
"dolor"
"amet,"
"elit,"
"tempor"
"magna"
"sit"
"sed"
"do"
"ut"
"et"
The sort()
function also lets you specify a reverse sort - after the by
and lt
functions (if used) have done their work, a true value passed to rev
reverses the result.
二维数组排序
[编辑]In Julia 1.0, you can sort multidimensional arrays with sortslices()
.
Here's a simple array of nine strings (you can also use numbers, symbols, functions, or anything that can be compared):
julia> table = ["F" "B" "I"; "A" "D" "G"; "H" "C" "E"] 3×3 Array{String,2}: "F" "B" "I" "A" "D" "G" "H" "C" "E"
You supply a number or a tuple to the dims
("dimensions") keyword that indicates what you want to sort. To sort the table so that the first column is sorted, use 1
:
julia> sortslices(table, dims=1) 3×3 Array{String,2}: "A" "D" "G" "F" "B" "I" "H" "C" "E"
Note that sortslices
returns a new array. The first column is in alphabetical order.
Use dims=2
to sort the table so that the first row is sorted:
julia>> sortslices(table, dims=2) 3×3 Array{String,2}: "B" "F" "I" "D" "A" "G" "C" "H" "E"
Now the first row is in alphabetical order.
If you want to sort by something other than the first item, pass a function to by
. So, to sort rows so that the middle column is in alphabetical order, use:
julia> sortslices(table, dims=1, by = x -> x[2]) 3×3 Array{String,2}: "F" "B" "I" "H" "C" "E" "A" "D" "G"
sortslices
has most of the options that you'll find in sort
, and more besides. You can reverse the order with rev
, change the comparator with lt
, and so on.
元组
[编辑]A tuple is an ordered sequence of elements, like an array. A tuple is represented by parentheses and commas, rather than the square brackets used by arrays. Tuples are mostly good for small fixed-length collections — they're used everywhere in Julia, for example, as argument lists and for returning multiple values from functions.
The important difference between arrays and tuples is that tuples are immutable. Other than that, tuples work in much the same way as arrays, and many array functions can be used on tuples too:
julia> t = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10) (1,2,3,4,5,6,7,8,9,10)
julia> t (1,2,3,4,5,6,7,8,9,10)
julia> t[6:end] (6,7,8,9,10)
You can have two-dimensional tuples:
julia> t = ((1, 2), (3, 4)) ((1,2),(3,4))
julia> t[1] (1,2)
julia> t[1][2] 2
But you can't change a tuple:
julia> t[1] = 0 LoadError: MethodError: no method matching set index!...
And, because you can't modify tuples, you can't use any of the functions like push!()
that you use with arrays:
julia> a = [1,2,3]; julia> push!(a,4) 4-element Array{Int64,1}: 1 2 3 4
julia> t = (1,2,3); julia> push!(t,4) LoadError: MethodError: no method matching push!
命名的元组
[编辑]A named tuple is like a combination of a tuple and a dictionary. Like a tuple, a named tuple is ordered and immutable, and enclosed in parentheses; like a dictionary, each element has a unique key that can be used to access it.
You can create a named tuple by providing keys and values directly:
julia> shape1 = (corner1 = (1, 1), corner2 = (-1, -1), center = (0, 0)) (corner1 = (1, 1), corner2 = (-1, -1), center = (0, 0))
To access the values, use the familiar dot syntax:
julia> shape1.corner1 (1, 1) julia> shape1.center (0, 0) julia> (shape1.corner1, shape1.corner2) ((1, 1), (-1, -1))
You can access all the values (destructuring) as with ordinary tuples:
julia> c1, c2, centerp = shape1; julia> c1 (1, 1) julia> c2 (-1, -1)
or just some of them:
julia> c1, c2 = shape1; julia> c1 (1, 1)
julia> c2 (-1, -1)
Elements can be the same type, or different types, but the keys will always be variable names.
You can iterate over a named tuple:
julia> for i in shape1 @show i end i = (1, 1) i = (-1, -1) i = (0, 0) julia> for i in shape1 println(first(i)) end 1 -1 0
Another way to create a named tuple is to provide the keys and values in separate tuples:
julia> ks = (:corner1, :corner2) (:corner1, :corner2) julia> vs = ((10, 10), (20, 20)) ((10, 10), (20, 20)) julia> shape2 = NamedTuple{ks}(vs) (corner1 = (10, 10), corner2 = (20, 20)) julia>shape2.corner1 (10, 10) julia> shape2.corner2 (20, 20)
You can combine two named tuples to make a new one:
julia> colors = (top = "red", bottom = "green") (top = "red", bottom = "green") julia> merge(shape2, colors) (corner1 = (10, 10), corner2 = (20, 20), top = "red", bottom = "green")
You can use existing variables for keys:
julia> d = :density; julia> (corner1 = (10, 10), corner2 = (20, 20), d => 0.99)
(corner1 = (10, 10), corner2 = (20, 20), density = 0.99)
Making single value Named Tuples requires a strategically-placed comma:
julia> shape3 = (corner1 = (1, 1),) (corner1 = (1, 1),)
julia> typeof(shape3) NamedTuple{(:corner1,),Tuple{Tuple{Int64,Int64}}}
If you forget it, you'll see this:
julia> (corner1 = (1, 1)) (1, 1) julia> typeof(corner1) Tuple{Int64,Int64}
You can make new named tuples by combining named tuples together.
julia> shape3 = merge(shape2, colors) (corner1 = (10, 10), corner2 = (20, 20), top = "red", bottom = "green")
Use a comma after a single element named tuple:
julia> merge(shape2, (top = "green",)) (corner1 = (10, 10), corner2 = (20, 20), top = "green")
因为没有逗号,元组将被解释为 merge()
的带圆括号的关键字参数。
To iterate over the "keys", use the fieldnames()
and typeof()
functions:
julia> fieldnames(typeof(shape3)) (:corner1, :corner2, :top, :bottom)
so you can do:
julia> for key in fieldnames(typeof(shape3)) @show getindex(shape3, key) end getindex(shape3, key) = (10, 10) getindex(shape3, key) = (20, 20) getindex(shape3, key) = "red" getindex(shape3, key) = "green"
合并两个元组是明智的。例如,如果您有以下命名的元组:
julia> shape3 (corner1 = (10, 10), corner2 = (20, 20), top = "red", bottom = "green")
并且要添加中心点并更改顶部颜色:
julia> merge(shape3, (center = (0, 0), top="green")) (corner1 = (10, 10), corner2 = (20, 20), top = "green", bottom = "green", center = (0, 0))
将插入新值,并更改现有值。