当我运行它时,我得到这个错误“未定义的局部变量或方法last_idx”.我知道建议是始终初始化变量,但我不明白为什么.毕竟first_idx和last_idx总是会在循环中得到一个值,因为参数字母总是出现在字符串中(在这个特殊的问题中).
我真的很感激一些(简单的)洞察力.谢谢!
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
解决方法
Blocks define a new variable scope: variables created within a block
exist only within that block and are undefined outside of the block.
Be cautIoUs,however; the local variables in a method are available to
any blocks within that method. So if a block assigns a value to a
variable that is already defined outside of the block,this does not
create a new block-local variable but instead assigns a new value to
the already-existing variable.
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
这是另一种可能性.它使用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],"d"=>[10]}