ブログ

読んで思い出す。忘れるために書く

配列から範囲を生成する

思いついたので書く

課題設定

与えられた1次元配列を順次捜査して、現在位置からひとつ前を参照しつつ、それと現在の要素とを合成した Range オブジェクトを作りたい

そのとき、処理結果として見たときの範囲は被らないようにしたい

入力値の例

[1, 5, 10]

期待する出力

[0..1, 2..5, 6..10]

書いたコード

if は振り分けに徹してもらった (`・ω・´)

def solver(list = [], previous = nil, ret = [])
  return ret if list.size.zero?

  current = list.shift

  ret << _ =
    if previous.nil?
      Range.new(0, current)
    else
      Range.new(previous, current)
    end

  solver(list, current + 1, ret)
end

data = [1, 5, 10]
solver(data.sort.uniq)
# => [0..1, 2..5, 6..10]
  • ret << _ = しているのは、「振り分けと代入」「代入から push」としたほうが、コードを読むときのリズムが保てる気がした
  • 変数名に _ を用いているのは 特に用途が ret に push するだけで、他に使わない(「特に限定的な変数」が複数有ったら _foo, _bar みたいに名前を付けてあげる)
  • 「(現在の値の)ひとつまえ」とか後ろとか、時間が関わる部分は ひとが混乱しやすいので、予め最初から使えるように定義して、現在だけ考えればいいようにしておくと、アタマの負担が減らせるかもしれない

Tips: 非破壊操作にこだわるなら、.shift せず .first にして、再帰呼び出しの時に solver(list - [current], current + 1, ret) とかできそう