leaning diary Rails

【Learning Diary7】不正な値を除外する

06/10/2023

不正な値を除外するrubyコードを考えました。

昨日、正規表現で作成したコードについて修正。

理由は「-5」を「5」として受けいれてしまえるためです。

以下のメソッドを使って考えます。

String#split

split(sep = $;, limit = 0) -> [String]
split(sep = $;, limit = 0) {|s| ... } -> self

sep で指定されたセパレータによって文字列を limit 個まで分割、結果を文字列の配列で返します。

ブロックを指定すると、配列を返す代わりに分割した文字列でブロックを呼び出します。

ブロックなしの場合は配列が返ります。

instance method String#split

to_i

to_i(base = 10) -> Integer

文字列を 10 進数表現された整数であると解釈し、整数に変換します。

class String to_i

Array#filter

filter -> Enumerator
select {|item| ... } -> [object]
filter {|item| ... } -> [object]

ブロックを評価した値が真であった要素を全て含む配列を返します。

真になる要素がひとつもなかった場合は空の配列を返却します。

arrayクラスのインスタンスメソッドですが、引数にブロックを与えない場合は配列ではなくEnumeratorを返します。

instance method Array#filter

Numeric#positive?

positive? -> bool

self が 0 より大きい場合に true を返します。

そうでない場合に false を返します。

instance method Numeric#positive?

instance method Array#uniq

uniq -> Array
uniq {|item| ... } -> Array

配列から重複した要素を取り除いた新しい配列を返します。

取り除かれた要素の部分は前に詰められます。

instance method Array#uniq

たくさんメソッドをつなげたり入れ替えたりしたときには、処理によってレシーバのデータ型や注意が必要と実感しました。

uniqの場合

to_iの前にuniqを適用すると、「01」と「1」が異なるため重複として処理されません。

irb#1(main):133:0> "2,2,6,弐,⑧,0,,-5,01,1,Ⅳ".split(",").uniq.map(&:to_i).filter(&:positive?)
=> [2, 1, 1]

irb#1(main):134:0> "2,2,6,弐,⑧,0,,-5,01,1,Ⅳ".split(",").map(&:to_i).uniq.filter(&:positive?)
=> [2, 1]

irb#1(main):135:0> "2,2,6,弐,⑧,0,,-5,01,1,Ⅳ".split(",").map(&:to_i).filter(&:positive?).uniq
=> [2, 1]

filterの場合

map適用後は配列のデータは返されますが、ブロック内の処理で要素がハッシュ型に変換されているとエラーが生じてしまいます。

irb#1(main):152:0> "2,2,6,弐,⑧,0,,-5,01,1,Ⅳ".split(",").map(&:to_i).uniq.filter(&:positive?).map{|num| { "id" => num }}
=> [{"id"=>2}, {"id"=>1}]

irb#1(main):155:0> "2,2,6,弐,⑧,0,,-5,01,1,Ⅳ".split(",").map(&:to_i).map{|num| { "id" => num }}.uniq.filter(&:positive?)
(irb#1):155:in `filter': undefined method `positive?' for {"id"=>2}:Hash (NoMethodError)

また、繋げることで可読性が下がり複雑性が増してしまうとよくありません。

過剰な場合はrubocop でも警告が表示されます。

app/forms/bill_group_form.rb:119:5: C: Metrics/PerceivedComplexity: Perceived complexity for xxxxxxxxxxxxxxxxxxxxxxx is too high. [9/8]

    def xxxxxxxxxxxxxxxxxxxxxxx

    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

-leaning diary, Rails