3

各ブロックをインジェクトに変換するためにリファクタリングを実行しようとしましたが、機能せず、理由がわかりません。

リファクタリングの前に機能するコードは次のとおりです。

class String
  # Build the word profile for the given word. The word profile is an array of
  # 26 integers -- each integer is a count of the number of times each letter
  # appears in the word. 
  #
  def profile
    profile = Array.new(26) { 0 }
    self.downcase.split(//).each do |letter|
      # only process letters a-z
      profile[letter.ord - 'a'.ord] += 1 unless letter.ord > 'z'.ord
    end
    profile
  end
end

動作しないリファクタリングは次のとおりです。

class String
  # Build the word profile for the given word. The word profile is an array of
  # 26 integers -- each integer is a count of the number of times each letter
  # appears in the word. 
  #
  def profile
    self.downcase.split(//).inject(Array.new(26) {0}) do |profile, letter|
      # only process letters a-z
      profile[letter.ord - 'a'.ord] += 1 unless letter.ord > 'z'.ord 
    end
  end
end

リファクタリングされたメソッドを実行しようとすると、

`block in profile': undefined method `[]=' for 1:Fixnum (NoMethodError)

それを正しく理解していれば、リファクタリングされたバージョンのプロファイルオブジェクトの配列参照演算子とは異なります。これは、injectに渡されたイニシャライザーが機能していないことを意味します。その理解は正しいですか?もしそうなら、なぜですか?

ありがとう!

4

1 に答える 1

3

この[]=メソッドは割り当てられた値を返すためprofile、次の反復でのの値は1になります(最後の反復の値であるため)。必要な動作を実現するには、次のことを行う必要があります。

self.downcase.split(//).inject(Array.new(26) {0}) do |profile, letter|
  # only process letters a-z
  profile[letter.ord - 'a'.ord] += 1 unless letter.ord > 'z'.ord 
  profile
end

また

self.downcase.split(//).inject(Array.new(26) {0}) do |profile, letter|
  # only process letters a-z
  profile.tap { profile[letter.ord - 'a'.ord] += 1 unless letter.ord > 'z'.ord }
end
于 2010-09-27T05:22:39.743 に答える