ESS多版本 【TA】【ESS】05 范围和遍历

TAAAAAAA

天王
管理成员
2024/06/16
200
3
27
1,210
5: Ranges and for-loops 范围和遍历

There’s yet another data type to introduce now, and that’s Range. A Range is, as the name suggests, a range of numbers with a start and an end. If you want to make a range with the number 1, 2, 3 and 4, you have two options:

有一种数据类型叫做范围,我们来看下面的这个例子:

Ruby:
r = 1..4
print r #=> 1..4 (1, 2, 3, and 4)

r = 1...5
print r #=> 1...5 (1, 2, 3, and 4)

# 范围就是从某一个数到某一个数,从左往右,从小到大,这两个数称为端点。
# 原作者说端点必须是整数,实际上浮点数也是可以的。
# 我们发现可以有两种写法,这两种写法的区别就是中间的点的个数,
# 如果有两个点,范围就是包括了后面的这个数,
# 如果有三个点,范围就是不包括后面的这个数。

You first type a number, 1 in this case (can also be negative). If you then write down two dots, you’re including the number written down after the dots. If you write down three dots, you’re excluding the number written down after the dots. So 1..4 starts at 1 and includes up to 4. 1...5 starts at 1 and goes up to 5, but doesn’t include it.

You can also have negative ranges.
-7..-3 (-7, -6, -5, -4, and -3)
-2..2 (-2, -1, 0, 1, and 2)

You can’t have ranges go from big to small, though. You can’t use Floats either.
2..-2 is empty. Just like an empty array, [], this is empty. Nothing.
1.1..1.3 is also empty. It won’t work when you try to do anything with it (regardless of using parentheses)

同样的,也支持负数的范围,比如说-2..2,就是指从-2到2,并且包括2。

Naturally, ranges also work with variables.

我们来看下面这个使用变量来作为范围的两个端点的例子:

Ruby:
a = 1
b = 4
print a..b #=> 1..4
print a...b #=> 1...4
print (a)...(b) #=> 1...4
print ((a)..(b)) #=> 1..4

The parentheses don’t make a difference, as long as they’re valid.
 
最后编辑:

TAAAAAAA

天王
管理成员
2024/06/16
200
3
27
1,210
Iterating through ranges 通过范围进行迭代

If you want to take each number in a range and do something with it (printing it out, for instance), you’d use for-loops. These use the keyword for and iterate over every number in a range. This for keyword also has to be “closed” with end.

现在我们终于讲到迭代了。
关于迭代,不同的人有不同的称呼,有些人叫迭代,有些人叫遍历,有些人叫循环,叫什么并不重要,重要的是你要知道它到底是怎么个东西。
我个人觉得最最简单的说法的话,迭代其实就是对一些数据做处理。
说到“一些”,其实你应该就想到数组了,数组里就有一些数据,以及想到前面讲的范围,范围里也有一些数据。
接着是关于“处理”,我们其实可以根据不同的条件对这些“一些”数据进行处理,也就是说,并不是所有的数据都必须做一样的处理。
举个例子,我们可以对符合a条件的数据做A处理,符合b条件的数据做B处理,等等。

在原作者的教程中,原作者是使用for(对于)进行迭代的,现在的ESS已经全面不用for进行迭代了。
现在我们使用each(每一个)进行迭代,使用each是Ruby 1.9及以后的版本所推荐使用的迭代方式,因为它提供了更清晰的代码块定义,更好的可读性和一致性,并且能更自然地扩展到其他的可迭代对象,最后,each的写法是更加现代的和Rubyic(Ruby语言化)的。
在以后的例子中,我都会简要的补上使用each的写法。

我们来看下面的例子:

Ruby:
for i in 1..3
  print i
end

# 1..3.each do |i|
#  print i
# end
#
# 前面我们说到了“更清晰的代码块定义”,这里do(做)和end之间的部分就是代码块的定义部分。
# 可以看到有个类似绝对值一样的东西,|i|这里面的i其实就是一个临时变量,它其实就是
# 相当于i = 1,i = 2和i = 3。
# 当然,不管你写i,还是写number,都是一样的,你也可以这样写:
#
# 1..3.each do |number|
#  print number
# end
#
# 这样写的话就更清晰了。
# 你正在对一个范围进行迭代,并且通过number显示出每一个迭代的目标是一个数字。
#
# Consecutively prints out:
# => 1
# => 2
# => 3
# 不管是哪种写法,这里的结果都是打印出每一个数字。

What this does is take every number in 1..3, which are 1, 2, and 3, and it does i = the number. It then runs the code inside the for-loop, which is print i in our case.

Important to note is that for-loops don’t introduce a new scope, which means the value of i will be overwritten in the loop.

Ruby:
i = 9
print i #=> 9
for i in 1..3
  print i #=> 1, 2, 3
end
print i #=> 3

# 这部分直接跳过,因为如果你使用each的话,并不会出现这个问题(可能大概是2.0之后的Ruby版本)。
# 用each时,代码块中的临时变量只在循环中使用,所以并不会影响到循环之外的同名变量。

At the last iteration of the for-loop, it essentially does i = 3. This isn’t reversed, so i becomes 3 outside of the loop, too. This is because it’s the same scope. Look at it like this:

Ruby:
# Outside the loop
i = 9
print i #=> 9


# Inside the loop
i = 1
print i #=> 1

i = 2
print i #=> 2

i = 3
print i #=> 3


# Outside the loop
print i #=> 3
 
最后编辑:

TAAAAAAA

天王
管理成员
2024/06/16
200
3
27
1,210
Iterating through arrays with ranges 通过范围迭代数组

The array ["one","two","three"] has indexes ranging from 0 to 2. We’d write this as 0..2 or 0...3. The size of the array is 3. If we wanted to setup a range that corresponds with an array’s indexes, we’d start at 0, because that’s where array indexes start, and then we have to use either ..2 or ...3. Since array.size would give us 3, it’s easiest to use ...3.

Ruby:
a = ["one","two","three"]
print a.size #=> 3
print 0...(a.size) #=> 0...3
print 0...a.size #=> 0...3
print 0..a.size - 1 #=> 0..2
print 0..(a.size - 1) #=> 0..2

Again, the parentheses don’t make any difference.

The range 0...3 contains 0, 1, and 2 - the same indexes as in the array. This means that if we iterate through this 0...3 range and use them as indexes in the array, we get every single element in the array.

Ruby:
a = ["one","two","three"]
print a.size #=> 3
r = 0...a.size
print r #=> 0...3

for i in r # Rather than 'for i in 0...3', 'for i in var' works, too.
  print a[i] #=> "one", then "two", then "three"
end

We usually skip the extra variable for the range.

Ruby:
a = ["one","two","three"]
for i in 0...a.size
  print a[i] #=> "one", then "two", then "three"
end

# 这一小节主要是介绍了如何对数组进行迭代,我只能说用for的写法实在是太麻烦了。
# 我们来看一下用each的写法:
#
# a = ["one","two","three"]
# a.each do |string|
#   print string #=> "one", then "two", then "three"
# end
#
# 这样就好了,我们并不需要进行乱七八糟的转化,使用each可以直接对数组中的
# 每一个元素进行迭代,这个就是前面说的“能更自然地扩展到其他的可迭代对象”。
#
# 那么each能否通过元素的序号进行迭代呢?
# 当然可以,请看下面的例子:
#
# a = ["one","two","three"]
# a.each_with_index do |string, index|
#   print a[index] #=> "one", then "two", then "three"
# end
#
# 我们可以在迭代的代码块里传入index,也就是元素的序号。
# 这种写法实际上就和原作者给的例子一样了,但是,这种写法其实是冗余的。

And that’s your typical array loop!
 

TAAAAAAA

天王
管理成员
2024/06/16
200
3
27
1,210
Iterating through enumerables 通过枚举迭代

本小结直接跳过,因为前面的小结已经全部说过了。

Another way to iterate over an array which may be more practical at times, is to iterate over it directly rather than using indexes. Imagine this setup:

Ruby:
a = ["one","two","three"]
print a[0] #=> "one"

e = a[0]
print e #=> "one"

e = 7
print e #=> 7
print a[0] #=> "one"

We assign a new variable called e and set it to the first element of the a array, which is “one”. Since that’s now a new variable, if we change its value, the value of the first element in the array won’t change - only that new variable will.

If we take this concept and use it inside a for-loop, we get something a little bit like this:

Ruby:
array = ["one","two","three"]
for e in array # You can also do 'for e in ["one","two","three"]
  print e #=> "one", then "two", then "three"
end

What we’re doing here is iterating through each element directly. First it does e = “one”, then e = “two”, and then e = “three”, rather than the indexes.

You can change the value of e, too. It just won’t affect the array being iterated through.

Ruby:
array = [1, 2, 3]
for e in array
  e *= 2 # the same as e = e * 2
  print e #=> 2, then 4, then 6
end
print array #=> [1,2,3]

However, if you were to do this with indexes, you are actually changing the array:

Ruby:
array = [1, 2, 3]
for i in 0...array.size
  array[i] *= 2 # We're directly modifying the array here
  print array[i] #=> 2, then 4, then 6
end
print array #=> [2, 4, 6]
 

TAAAAAAA

天王
管理成员
2024/06/16
200
3
27
1,210
Calling methods on ranges 在范围中调用方法

本小结直接跳过。
本小结说的是1..4.include?(2)和(1..4).include?(2)的区别。
作者说前一种写法是错的,但是实际上前一种写法也是可以的。
这一行代码的意思是检查2是否在1到4(包括4)内。

There’s just one method on ranges that’d be useful to know for now, and that’s include?(n). Just like with arrays, it will return true if n is included in the range, and false if not.

Ruby:
# 这里是——
# ,and that’s include?(n). Just like with arrays,

You have to be careful when calling a method on a range though. If you were to type something like this:

Ruby:
print 1..4.include?(2)

...It’ll raise an error. Internally, it’s seen like so:

Ruby:
print (1)..(4.include?(2))

...And there isn’t a method called include? on Fixnums.
So to make sure you’re actually calling the method on the range and not on a Fixnum, you should surround the range with parentheses.

Ruby:
print (1..4).include?(2) #=> true
print (1..4).include?(3.14) #=> true # 这里应该错了,结果应该是false。

This is one of the only instances where parentheses with ranges really matter.

本章完。
 

在线成员

论坛统计

主题
474
消息
2,137
成员
2,909
最新成员
小灵喵~