Julia语言程序设计
上QQ阅读APP看书,第一时间看更新

5.3.2 for

另外一种循环由关键字for构建,与while的用法有很大的不同。在for循环中,控制循环的不再是条件表达式,而是遍历型表达式。其基本表述结构为:


for 遍历表达式
  # 语句块
end

其中,“遍历表达式”需要可迭代数据结构的支持。

一般而言,在数集迭代时便会驱动循环体的语句块一次次地执行;而循环的次数便是数集中可遍历到的元素个数。同时,遍历表达式本身会提供循环变量,用于逐一提取数集中的元素值,以便循环内部进行相应的处理。

Julia中提供了三种基本的遍历表达方式,如下:


for 循环变量 = 可迭代数据集
  # 更多语句
end

for 循环变量 in 可迭代数据集
  # 更多语句
end

for 循环变量 ∈ 可迭代数据集
  # 更多语句
end

其中,三个遍历操作符=、in及∈是等价的,可以任选一个。

所谓可迭代数据集,主要是指后面介绍的元组(Tuple)、字典(Dict)及集合(Set),或者数组(Array)及范围表达式(Range)等。为了叙述方便,这里作简单的说明:元组的形式为(1,2,3),一旦创建内部元素不能再变更;数组是多维数据序列,以中括号表达,例如[1,2,3]或[123]便是有三个元素的数组;而范围表达式则用于表达等差序列,是一种迭代器,例如1:10表示公差为1的整数序列,取值1到10共计10个元素。

下面我们以实例来了解for循环的使用,例如:


julia> for i = 1:5
         print(i, " ")
       end
1 2 3 4 5

julia> for i in 1:5
         print(i, " ")
       end
1 2 3 4 5

julia> for i ∈ 1:5
         print(i, " ")
       end
1 2 3 4 5

或者:


julia> for i = [1 2 3 4 5]
         print(i, " ")
       end
1 2 3 4 5

julia> for i in [1 2 3 4 5]
         print(i, " ")
       end
1 2 3 4 5

julia> for i ∈ [1 2 3 4 5]
         print(i, " ")
       end
1 2 3 4 5

又或者:


julia> for i = (1,2,3,4,5)
         print(i, " ")
       end
1 2 3 4 5

julia> for i in (1,2,3,4,5)
         print(i, " ")
       end
1 2 3 4 5

julia> for i ∈ (1,2,3,4,5)
         print(i, " ")
       end
1 2 3 4 5

在for循环中,还支持同时对多个数据集进行遍历,例如:


julia> for i = 1:2, j = (1,2,3,4,5)
         print((i,j), " ")
       end
(1, 1) (1, 2) (1, 3) (1, 4) (1, 5) (2, 1) (2, 2) (2, 3) (2, 4) (2, 5)

而且遍历操作符也可以混用,例如:


julia> for i = [1 2 3 4 5], j in 3:4
         print((i,j), " ")
       end
(1, 3) (1, 4) (2, 3) (2, 4) (3, 3) (3, 4) (4, 3) (4, 4) (5, 3) (5, 4)

在这种多遍历的表达中,得到的循环变量组合实际是每个数据集的笛卡尔积。也正因如此,遍历操作的顺序影响着内部语句中循环变量的取值。如果更换遍历操作的顺序,将会得到不同的结果。例如:


julia> for j = (1,2,3,4,5), i=1:2
         print((i,j), " ")
       end
(1, 1) (2, 1) (1, 2) (2, 2) (1, 3) (2, 3) (1, 4) (2, 4) (1, 5) (2, 5)

julia> for j in 3:4, i = [1 2 3 4 5]
         print((i,j), " ")
       end
(1, 3) (2, 3) (3, 3) (4, 3) (5, 3) (1, 4) (2, 4) (3, 4) (4, 4) (5, 4)

可见与上述的运行结果不同。其中的i或j虽然仍出自同一数集,但因为遍历顺序的不同,循环变量的组合出现了差异。

还有一点需要注意,每一个遍历表达式之间的分割符是逗号而非是分号。如果使用分号,则会产生出乎意料的结果。例如:


julia> for i=1:2; j=3:4
         print((i,j), " ")
       end
(1, 3:4)  (2, 3:4)

可见只执行了2次循环,而不是4次;而且j的值不再是元素,也没有实现笛卡尔积。这是因为i=1:2;j=3:4这种表达不再是遍历表达式,而是复合表达式。

当然,在for循环中,我们同样可以使用break与continue来控制循环的运行。例如:


julia> for i = 1:1000
         print(i, " ")
         if i >= 5
           break
         end
       end
1 2 3 4 5

例中的i在遍历表达中可以取到1000个数值,但因内部的if语句要求i>=5时break(中断循环),所以该循环只实际执行了5次。再例如:


julia> for i = 1:10
         if i % 3 != 0
           continue                       # 重新跳到 for i = 1:10
         end
         println(i)
       end
3
6
9

即只有在i是3的倍数的时候,才会将i的值打印出来。

另外,在for循环中,continue的运作与在while中的表现是相同的,也同样只会影响其所处的内层循环,不会波及外层循环。例如:


julia> for j = 1:5
         println("\nloop ", j)  # \n为换行符,便于查看结果
         for i = 1:10
           if i % 3 != 0
             continue           # 重新跳到 for i = 1:10
           end
           print(i, " ")
         end
       end

loop 1
3 6 9
loop 2
3 6 9
loop 3
3 6 9
loop 4
3 6 9
loop 5
3 6 9

其中由j控制的外层循环完整地运行了5次,而由i控制的内层循环只在i为3的倍数时完整地运行了3次,但实际仍运行了10次。