首先,until 是一个顶级测试循环。在再次测试until 条件之前,整个块必须循环;在循环中的每个语句之后都不会对其进行测试。您必须先到达end 或next,until 才会再次评估。
其次,<statement> if <condition> 是 if <condition> <statement> end 的 ruby 简写。它允许您在不牺牲可读性的情况下在一行上编写一个简单的条件。 next 只会在arr.each_index 循环的最后一次迭代中执行,向上堆栈到until 条件,此时sorted 将被设置为false。
要查看其工作原理,请尝试运行以下修改:
#!/usr/bin/ruby
def sorting(arr)
puts "starting with #{arr}"
sorted = false
until sorted
sorted = true
arr.each_index do |i|
if i == arr.length - 1
puts "'next' when i == #{i}, arr = #{arr}"
next
end
if arr[i] > arr[i + 1]
puts "swapping at #{i}: #{arr[i]} <=> #{arr[i+1]}"
arr[i], arr[i+1] = arr[i+1], arr[i]
sorted = false
end
end
end
arr
end
p sorting([7,4,5,1,2,3])
这个程序的输出是:
starting with [7, 4, 5, 1, 2, 3]
swapping at 0: 7 <=> 4
swapping at 1: 7 <=> 5
swapping at 2: 7 <=> 1
swapping at 3: 7 <=> 2
swapping at 4: 7 <=> 3
'next' when i == 5, arr = [4, 5, 1, 2, 3, 7]
swapping at 1: 5 <=> 1
swapping at 2: 5 <=> 2
swapping at 3: 5 <=> 3
'next' when i == 5, arr = [4, 1, 2, 3, 5, 7]
swapping at 0: 4 <=> 1
swapping at 1: 4 <=> 2
swapping at 2: 4 <=> 3
'next' when i == 5, arr = [1, 2, 3, 4, 5, 7]
'next' when i == 5, arr = [1, 2, 3, 4, 5, 7]
[1, 2, 3, 4, 5, 7]
这当然是学术性的:对数组进行排序的正确方法是使用Array#sort。
注意:next 只是必要的,因为在each_index 循环的最后一次迭代中,i + 1 将超出数组的范围,这将导致访问arr[i + 1] 的下一行失败(它将评估为nil,并且您无法将整数与 nil 进行比较)。这样做的替代方法是修改交换测试索引周围的条件,或者将枚举数组的循环外部更改为更小的范围。
修改条件,消除next,因为逻辑和条件是从左到右评估的,解释器在第一个为假时立即停止:
def sorting(arr)
sorted = false
until sorted
sorted = true
arr.each_index do |i|
if (i < arr.size - 1) && (arr[i] > arr[i + 1])
arr[i], arr[i+1] = arr[i+1], arr[i]
sorted = false
end
end
end
arr
end
p sorting([7,4,5,1,2,3])
改变循环的范围,这样循环执行次数更少:
def sorting(arr)
sorted = false
until sorted
sorted = true
(0..arr.size - 2).each do |i|
if (arr[i] > arr[i + 1])
arr[i], arr[i+1] = arr[i+1], arr[i]
sorted = false
end
end
end
arr
end
p sorting([7,4,5,1,2,3])
next 类似于其他语言中的goto,应尽可能避免使用。