尋常でないもふもふ

a software engineer blog

Rubyでarray.each_index.injectしたときの括弧は配列展開

こういうやつ

animals = {
  a1: { name: '', type: '哺乳類' },
  a2: { name: '', type: '哺乳類' },
  a3: { name: '蜥蜴', type: '爬虫類' }
}
mammals = animals.reduce([]) do |arr, (id, animal)| # <- ここの丸括弧
  (animal[:type] == '哺乳類') ? (arr << animal) : arr
end

実用例

「プレイヤーID」と「スコア」を持つハッシュがあるとして

player = { id: 1, score: 100 }

あるチームに所属する「プレイヤー毎のスコア」の合計値を独自に算出して「チームのスコア(≒チームの強さ)」を表したい。スコアの計算方法は、Clash of Clan のクランポイント計算と同様に、チーム内で1〜10位は各プレイヤーのスコアの50%、11〜30位は25%といった感じで係数が変わる。
これを Ruby で実装すると配列をイテレートしながら計算するために inject を使うことになるが、プログラムを書く上で配列のインデックスが必要な場合は each_with_index を挟むことになる。

# スコアが高い順にソート
players.sort_by { |player| -player[:score] }
# チーム内で上位にあるほどスコアを高く評価、51位以下は無視
players.each_with_index.inject(0) do |sum, (player, i)|
  sum +=
    case i + 1
    when  1..10 then (score * 0.50).round
    when 11..20 then (score * 0.25).round
    when 21..30 then (score * 0.12).round
    when 31..40 then (score * 0.10).round
    when 41..50 then (score * 0.03).round
    end
end

このとき引数に sum, (player, i) という謎の丸括弧がでてくるが、これは配列を意味する。

players.each_with_index.inject(0) do |sum, arr|
  sum, player = arr

このコードと同じ意味となり、引数内で展開してくれているだけ。

JavaScript でいうところの 分割代入(Destructuring assignment)