请有人向我解释,为什么不初始化 first_idx 和 last_idx 导致代码无法运行?
当我运行它时,我收到此错误"未定义的局部变量或方法last_idx" 。我知道建议总是初始化变量,但我不明白为什么。毕竟first_idx和last_idx总是会在循环中得到一个值,因为参数 lette r总是出现在字符串中(在这个特殊问题中)。
我非常欣赏一些(简单)洞察力。谢谢!
P.S,我也知道在Ruby中使用#index和#rindex很容易解决问题,但我不允许使用简单的方法解决它。
def find_for_letter(string, letter)
first_idx = nil
0.upto(string.length - 1) do |idx1|
if string[idx1] == letter
first_idx = idx1
break
end
end
last_idx = nil
(string.length - 1).downto(0) do |idx2|
if string[idx2] == letter
last_idx = idx2
break
end
end
if last_idx == first_idx
return [first_idx]
else
return [first_idx, last_idx]
end
end
def first_last_indices(word)
h = {}
word.chars.each do |char|
h[char] = find_for_letter(word, char)
end
h
end
答案 0 :(得分:6)
Blocks定义一个新的变量scope:在块中创建的变量 仅存在于该块内,并且在块外部未定义。 但是要小心;方法中的局部变量可用 该方法中的任何块。因此,如果一个块为a赋值 已经在块外部定义的变量,但事实并非如此 创建一个新的块局部变量,但是为其分配一个新值 已存在的变量。
a = 0
2.times do
a = 1
end
puts a #=> 1
b = 0
2.times do |i;b| # <- b will stay a block-local variable
b = 1
end
puts b #=> 0
2.times do |i|
c = 1
end
puts c #=> undefined local variable or method `c' for main:Object (NameError)
这是一个更小的方法来实现目标。 它为每个字符保留一个带有minmax索引的哈希值。
默认哈希值是一个空数组。
该方法遍历每个字符(带索引)。
如果minmax数组已包含2个值:
def first_last_indices(word)
minmax_hash = Hash.new { |h, k| h[k] = [] }
word.each_char.with_index do |char, index|
minmax = minmax_hash[char]
if minmax.size == 2
minmax[1] = index
else
minmax << index
end
end
minmax_hash
end
p first_last_indices('hello world')
{"h"=>[0], "e"=>[1], "l"=>[2, 9], "o"=>[4, 7], " "=>[5], "w"=>[6], "r"=>[8], "d"=>[10]}
这是另一种可能性。它使用group_by来获取每个字符的所有索引,使用minmax来获取第一个和最后一个索引:
def first_last_indices(word)
word.each_char.with_index
.group_by{ |c, _| c }.map{ |c, vs|
[c, vs.map(&:last).minmax.uniq]
}.to_h
end
p first_last_indices('hello world')
{"h"=>[0], "e"=>[1], "l"=>[2, 9], "o"=>[4, 7], " "=>[5], "w"=>[6], "r"=>[8], "d"=>[10]}
答案 1 :(得分:5)
即使您没有声明last_idx
,您仍然可以在循环内初始化它,即:
(string.length - 1).downto(0) do |idx2|
if string[idx2] == letter
last_idx = idx2 # works absolutely fine
break
end
end
但请注意您声明变量的位置。它是一个局部变量,因此它与您所在的块相关联。现在当您尝试在块外部访问该变量时,您会收到错误:
未定义的局部变量或方法last_idx
要使变量在块外可用,您必须在外部声明它。这就是当你在为其分配值的块之前声明last_idx = nil
时你正在做的事情。
<强>更新强>
虽然通过使用实例变量可以避免声明,但最佳实践表明它应该用于这些变量所具有的信息与所有或几乎所有类相关的情况。另一方面,如果信息非常局限于这种特定方法,则使用局部变量。
答案 2 :(得分:4)
这就是局部变量的工作方式。
如果使用实例变量,Ruby会假设它们已在条件块内初始化,但不会用于局部变量。
develop
这很好用。