我需要一个循环来逐行读取文本但完全忽略第一行。我遇到了Nobuyoshi Nakada在线发布的非常方便的表达方式。此表达式跳过Enumerator的一次迭代。有人可以帮助解释评估的最后一步吗?这是举例说明。这段代码将打印1到5而不是0到5.我是编程新手,我不知道这是否是一个常见的解决方案。我花了3天才找到它!
(0..5).each do |i|
if (first=true)..false and first
next
end
puts i
end
我推荐使用if (first=true)..false and first
评估pry
,但无法深入了解。
(first=true)
评估为: true (first
的值为 true )
(first=true)..false
评估为: true .. false(first
的值仍为 true )
(first=true)..false and first
评估为: true .. false和 true , true 且 true (first
的值仍为 true )
if (first=true)..false and first
评估为:if( true ),执行 next 语句并退出 if 循环(值为first
现在 nil )
Enumerator的下一次迭代返回if (first=true)..false and first
表达式(第一个值仍 nil )
此步骤评估为 false :if(first = true)..false and nil
(左侧first
的值为 true ,右侧为的零(适用的假)
我迷失在这里......
问题:为什么if {@}的右侧first
未分配" true "。 first
的值似乎同时为真和为?我在这里错过了什么吗?
答案 0 :(得分:2)
几个关键见解:
left..right
中的{li> if
是一个触发器操作符,如JörgWMittag所述:它只评估左侧(和仅左侧)它是假的(返回该值),然后评估右侧(和仅右侧),只要它是真实的(返回true
),然后返回评估左侧。这允许您编写if (row == 5)..(row == 10)
之类的内容并获取从5到10的行(因为它从左侧返回false
从1到4,然后从true
从左侧返回5
然后翻转并评估右侧从6到10,每次返回true
,最后一次翻转到10;然后返回到返回false
左边的其余行侧)。
first
,所以它是一个作用于块的变量;这意味着它的值不会在步骤之间延续,并在每次迭代中重置为nil
所以:
(first = true)
为true
;触发器返回true
并翻转到右侧true and first
评估为true
;处理next
,循环循环。first
返回nil
false
- 它没有翻转,并返回true
。true and first
是false
; next
未评估first
将继续为nil
。答案 1 :(得分:2)
The flip-flop operator是从Perl继承的Ruby的一个有点模糊的特性(就像大多数Ruby的更加模糊的特性一样)。它是一种在true
和false
之间来回翻转和翻转的表达式。
基本上,它从false
开始,然后它翻转"翻转"只要左表达式评估为 truthy 对象,就true
,并且"翻转"只要右表达式计算为 truthy 对象,就会再次返回false
。
因此,条件以false
开头。 第一次通过循环, left 表达式计算为 truthy 值(在Ruby中,赋值计算为正在分配的值)并且作为副作用还会将true
分配给first
。由于 left 表达式的计算结果为 truthy ,因此触发器翻转为true
,整个条件现为true and true
,即true
{1}}。因此,我们执行条件表达式的主体,它只是next
,即跳过当前的迭代。
秒(以及所有其他时间)通过循环,触发器已经翻转到true
,所以现在我们只有检查右表达式,以便触发器再次翻转回false
。不再检查左表达式。好吧,正确的表达只是false
所以我们永远不会再次回到false
,触发器现在总是true
。但是,左表达式不会被评估(我们只检查右表达式何时再次翻转),这意味着永远不会执行first
的赋值,这意味着first
是初始化的局部变量,这意味着它的计算结果为nil
,这是 falsy ,这意味着true and nil
的计算结果为false
。对于循环的每次迭代,这将继续如此。
因此,这段代码以更加模糊的方式使用了一个模糊的特征(触发器)(不是作为条件,而是简单地用于#34;禁用"执行赋值)。这绝对是任何Rubyist都会编写的 not 代码。
是一种更惯用的方式(0..5).drop(1).each do |i|
puts i
end
或
(0..5).each.with_index do |n, idx|
next if idx.zero?
puts n
end
请注意,nobu是Ruby核心开发人员,日语,也是最早使用Ruby的人之一。日本的Ruby早期采用者是一个与更大的Ruby社区完全不同的子社区。很可能这实际上是日本Rubyists和/或Ruby核心开发人员中众所周知且易于理解的习惯用语。关于习语的事情是,如果你知道它们的样子并且你知道它们的意思,你就不需要理解它们,所以像这样的代码可能可以,如果这是惯用的。但它确实在较大的Ruby社区中不惯用。
答案 2 :(得分:-1)
(first=true)..false
对true..false
的评价是正确的,但这不是有效的陈述 - 它会引发ArgumentError: bad value for range
。
也许其他人了解这个解决方案是如何运作的,但我认为这绝对不是最简单或最简单的方法。
如果您的目标是获得N次输入并忽略N个输入,则可以执行以下操作:
num_times_to_ignore = 1
num_times_to_process = 3
# ignore some lines
num_times_to_ignore.times { gets.chomp }
# process each input individually
num_times_to_process.times.each { do_something_with(gets.chomp) }
# or you can get all the inputs before processing
results = num_times_to_process.times.map { gets.chomp }
results.each { |input| do_something_with(input) }