简体   繁体   English

触发器红宝石中3点范围操作符和2点范围操作符之间的差异

[英]Difference between 3-dot-range operator and 2-dot-range operator in flip flop ruby

Please help me to understand the difference between range operators ... and .. as "flip-flops" used in Ruby. 请帮助我理解范围运算符之间的区别.....作为Ruby中使用的“触发器”。

This is an example from Pragmatic Programmers guide to Ruby: 这是来自Pragmatic Programmers指南的示例:

a = (11..20).collect {|i| (i%4 == 0)..(i%3 == 0) ? i : nil}

which returns: 返回:

[nil, 12, nil, nil, nil, 16, 17, 18, nil, 20]

Also: 也:

a = (11..20).collect {|i| (i%4 == 0)...(i%3 == 0) ? i : nil}

returned: 回:

[nil, 12, 13, 14, 15, 16, 17, 18, nil, 20]

The flip/flop (aka f/f) is a stateful operator which originates from perl. 触发器(又名f / f)是源自perl的有状态运算符。

f/f operator is implied in conditional statements (if and ternary) in ruby instead of range so (1..5) is a range but (1..5) ? f / f运算符隐含在ruby中的条件语句(if和ternary)而不是range中,因此(1..5)是一个范围但是(1..5)? 1 : 5 is af/f. 1:5是af / f。 f/f has an internal state (true / false) and consists of two conditions. f / f具有内部状态(真/假)并且由两个条件组成。 It tuns ON(state becomes true) when it's first condition evaluates to true and OFF when it's second condition evalutes to true. 它在第一个条件评估为真时开启(状态变为真),在第二个条件评估为真时关闭。 The difference between two and three dotted versions is that two-dotted evaluates second condition immediately after the first one evaluated to true and three-dotted doesn't. 两个和三个虚线版本之间的区别在于,双点在第一个评估为真后立即评估第二个条件,三点不评估。

two dotted version works like this: 两个虚线版本的工作原理如下:

A..B |
A -> false | State -> false
A -> true, B -> false | State -> true # notice how it checks both conditions
B -> false | State -> true
B -> true | State -> false
A -> false  | State -> false
A -> true, B -> true | State -> false

compare it to three dotted version 将它与三个虚线版本进行比较

A...B
A -> false | State -> false
A -> true | State -> true # three dotted version doesn't check second condition immediately
B -> false | State -> true
B -> true | State -> false
A -> false | State -> false
A -> true | State -> true

Let's follow along the amazing perl article but with examples in ruby 让我们沿着令人惊叹的perl文章,但在ruby中有例子

Two dotted example: 两个虚线示例:

DATA.each_line do |line|
  print "\t" if (line =~ /^start/ .. line =~ /^end/)
  print line
end

__END__
First line.
start
Indented line
end
Back to left margin

This prints: 这打印:

First line.
    start
    Indented line
    end
Back to left margin

as you can see - f/f turns ON on line 2 and OFF on line 4. Yet there is a subtlety to it. 正如你所看到的那样 - f / f在第2行打开,在第4行打开。但它有一个微妙之处。 Check this out: 看一下这个:

DATA.each_line do |line|
  print "\t" if (line =~ /start/ .. line =~ /end/)
  print line
end
__END__
First line.
Indent lines between the start and the end markers
Back to left margin

This prints: 这打印:

First line.
    Indent lines between the start and the end markers
Back to left margin

There it turns ON on line 2 and immediately turns OFF. 它在第2行打开并立即关闭。

Let's imagine that you don't want to check the second operator immediately after the first. 让我们假设您不想在第一个操作符之后立即检查第二个操作符。 It's where three-dotted f/f becomes handy. 这是三点式f / f变得方便的地方。 Check out the next example. 看看下一个例子。

DATA.each_line do |line|
  print "\t" if (line =~ /start/ ... line =~ /end/)
  print line
end

__END__
First line.
Indent lines between the start and the end markers
So this is indented,
and this is the end of the indented block.
Back to left margin

Which prints: 哪个印刷品:

First line.
    Indent lines between the start and the end markers
    So this is indented,
    and this is the end of the indented block.
Back to left margin

as you can see it turns ON on line 2 and OFF on line 4 你可以看到它在第2行打开,在第4行打开

Now let's apply this to your examples 现在让我们将它应用于您的示例

I wrote a small script to illustrate it's behaviour 我写了一个小脚本来说明它的行为

def mod(n, i)
  result = i % n == 0
  puts "#{i} mod #{n} => #{result}"
  result
end

(11..20).each { |i|
  if (mod(4, i))...(mod(3, i)) # NOTE it's a three dotted version
    # NOTE that those puts show previous state, not the current one!
    puts true
  else
    puts false
  end
}

two dotted result: 两个虚线结果:

11 mod 4 => false
false
12 mod 4 => true
12 mod 3 => true # Notice how it checks both conditions here
true
13 mod 4 => false
false
14 mod 4 => false
false
15 mod 4 => false
false
16 mod 4 => true
16 mod 3 => false
true
17 mod 3 => false
true
18 mod 3 => true
true
19 mod 4 => false
false
20 mod 4 => true
20 mod 3 => false
true

three dotted result: 三点结果:

11 mod 4 => false
false
12 mod 4 => true
true
13 mod 3 => false
true
14 mod 3 => false
true
15 mod 3 => true # turns OFF here
true
16 mod 4 => true # and turns immediately ON here
true
17 mod 3 => false
true
18 mod 3 => true
true
19 mod 4 => false
false
20 mod 4 => true
true
=> 11..20

PS Range and flip/flop are two completely distinct operators and you should not mix them up. PS Range和flip / flop是两个完全不同的运算符,你不应该混淆它们。

The concept of flip-flop switch actually came from electronics . 触发开关的概念实际上来自电子产品 The main advantage of it is that it remembers it's state. 它的主要优点是它记住了它的状态。 Consider flip-flop boolean range as a variable, storing boolean value. 将触发器布尔范围视为变量,存储布尔值。 Let's take a look at following example: 我们来看看下面的例子:

1.upto(10).each do |i|
  puts i if (i%2==0)..(i%4==0)
end

        #                        vvvv   value of “hidden” state
2       # left range boundary  ⇨ true
3
4       # right range boundary ⇨ false, no 5 follows 
6       # left range boundary  ⇨ true
7
8       # right range boundary ⇨ false, no 9 follows 
10

In your first example the “condition” became true for 4-multiples and turns back to false on 3-multiples. 在你的第一个例子中,“条件”对于4倍数变为true ,在3倍数时变为false In the second example the condition variable was not turned off on 12 just because the right range boundary ( i%3 ) is excluded , since it's a 3-dot-range. 在第二个例子中,条件变量在12上没有关闭,因为它排除了右边界( i%3 ),因为它是一个3点范围。

Hope the example was not too tangled. 希望这个例子不是太纠结。

The difference between 2 dots and 3 dots in Ruby is inclusion. Ruby中2点和3点之间的差异是包含。 For example 例如

(1..100)
=> All numbers starting from 1 and ending at 100 INCLUDING 100

(1...100)
=> All numbers starting from 1 that are less than 100

(1..100).include?(100)
=> true

(1...100).include?(100)
=> false

Hope this helps. 希望这可以帮助。

When a double dot is used in a range it creates a range of numbers which go up to and includes the maximum number passed in. When a triple dot is used it creates a range which goes up to but does NOT include the maximum number passed in. 当在一个范围内使用双点时,它会创建一系列数字,这些数字最多可包含传入的最大数量。当使用三点时,它会创建一个范围,该范围最多但不包括传入的最大数量。

So: 所以:

 (1..5).each {| i | puts i} #will print 1,2,3,4,5

While: 而:

(1...5).each {| i | puts i} #will print 1,2,3,4

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM