QA@IT

Array#slice(range) の補集合を取得するメソッド

4105 PV

Array#slice(range)の補集合を返すメソッドを書いたのですが、かなり冗長になってしまいました。
もう少しすっきりと書けないでしょうか?

アドバイスよろしくお願いします。

class Array
  def slice_remain(range)
    return [] if range.first > range.last
    before_array = slice(0..(range.first-1)) if range.first > 0
    after_array = slice((range.last+1)..-1) if range.last < size
    before_array ||= []
    after_array ||= []
    before_array + after_array
  end
end

a = [1,4,4,3]
a.slice(2..3) # => [4,3]
a.slice_remain(2..3) # => [1,4]

回答

お書きの物は、「レンジの両端が非負で、終端を含む」場合限定のようですが、それでいいなら、

def foo(range)
  reject.with_index{|x,i| range.include?(i)}
end

でいいかと思います。
負の始端・終端もありにすると、self.sizeを使って加算して非負に直してからということでしょうか。
さらに終端を含まないレンジへの対応も多分if文の追加でいけるかと。

編集 履歴 (0)
  • `reject`を使えばこんなにきれいに書けるんですね! ありがとうございます。 -

現状、以下の様なrangeを与えると

p [1,2,3,4,5,6].slice_remain(4..1)

以下の様な返却値になってしまいますね。

[1, 2, 3, 4, 3, 4, 5, 6]

勘違いだったらすみませんが、今のコードですと差集合ではだめなのですか?

  • コード
x= [1,2,3,4,5,6,7,8,9]

p x.slice_remain(3..5)

p x - x.slice(3..5)  # 差集合 
  • 結果
[1, 2, 3, 7, 8, 9]
[1, 2, 3, 7, 8, 9]
編集 履歴 (0)
  • バグの指摘ありがとうございます。そうですね、`4..1`等の場合は`nil`を返すようにします。差集合に関しては元の配列の要素が uniq でない場合があるので補集合でないと困るんですよね…。質問内容を編集しておきます。 -
ウォッチ

この質問への回答やコメントをメールでお知らせします。