Variables in a block
From the Ruby programming language :
Blocks define a new scope of variables: variables created in a block exist only inside this block and undefined outside the block. Be careful, however; local variables in the method are available for any blocks in this method. Therefore, if a block assigns a value to a variable that is already defined outside the block, it does not create a new local-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)
Code Refactoring
Iteration with Symbols and Index
Here a smaller method is used for your purpose. It stores a hash with minmax indices for each character.
The default hash value is an empty array.
The method iterates over each character (with index).
If the minmax array already contains 2 values:
- it replaces the second (maximum) current index.
- it adds the current index to the array otherwise.
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]}
With group_by
Here is another opportunity. It uses group_by to get all the indices for each character, and minmax to get only the first and last indices:
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]}