2016-12-09 7 views
1

私はRubyで次のコードを書いていますが、NoMethodError: undefined method '>' for nil:NilClassを得続けます。なぜそれが>だと思いますか?ruby​​より大きいnotethoderrorを取得する

def count_positives_sum_negatives(lst) 
    pos = 0 
    neg = 0 
    for i in 0..lst.length 
    if lst[i] > 0 
     pos += 1 
    elsif lst[i] < 0 
     neg += 1 
    end 
    end 
    return [pos, neg] 
end 
+0

あなたのインデックスは1つオフです(私の答えは下記参照) – manonthemat

+0

このメソッドは、ポジティブとネガをカウントします。それはネガを合計しません。なぜそれは 'count_positives_sum_negatives'と呼ばれていますか? 好奇心だけ、大丈夫ですか? –

+0

@Aetherusは最高の "Ruby way"答えをくれました。それを使用してください。 – moveson

答えて

2

をです。どうか、私を誤解しないでください。私は数年前にRubyを使い始めたときに聞いたことを繰り返すだけです:Rubyを学ぶことは、Rubyの構文を使うこと以上のものです。 1つはRubyのコアを探索し、Rubyのやり方をしようとする必要があります。

これはまさにここで起こります。質問に表示されているコードは、Rubyの方法からは遠いです。 @manonthematによって与えられた答えのコードもあります。

def count_positives_sum_negatives(lst) 
    result = [0,0] 
    lst.each { |el| (el > 0) ? result[0] += 1 : result[1] += 1 } 
    result 
end 

あるいはさらに良い:

に短縮することができ、両方のケースで

def count_positives_sum_negatives(lst) 
    lst.each_with_object([0,0]) { |el,arr| (el > 0) ? arr[0] += 1 : arr[1] += 1 } 
end 

puts count_positives_sum_negatives([5,7,-1,-4,4,4,5,-3]) 

を実行している

[5,3] 
につながります

each_with_objectを使用する2番目の形式は、最初の形式よりも優れています。ブロック内で使用するために外部に配列またはハッシュを宣言することは、Rubyではコードの匂いとみなされます。

私は方法の名前(count_positives_sum_negatives)が良くないことを指摘したいと思います。このメソッドは、陽性と陰性の両方をカウントし、それらのどれも合計しないため、メソッドが何をしているのかを表していません。確かにcount_positives_and_negativesはより良い名前になります。

ちなみに、@manonthematは、eachを使用すると範囲を基準にしたインデックスを繰り返すよりもはるかに良い方法であることを指摘すると完全に正しいです。ブロック内に実際にインデックスが必要な場合は、それを提供する方法がeach_with_indexです。

1

は、私がルビーを使用しましたので、しばらくしているが、私は、各

def count_positives_sum_negatives(lst) 
    pos = 0 
    neg = 0 
    lst.each { |el| 
    if el > 0 
     pos += 1 
    elsif el < 0 
     neg += 1 
    end 
    } 
    return [pos, neg] 
end 

しかし、あなたの質問に答えるために、あなたのインデックスがオフになっているを使用して反復する好ましい方法を覚えています。 ..には、右のものが含まれています。この場合、あなたのリストの長さは、最後のインデックスよりも1つ高いです。だからあなたはそのエラーメッセージを受け取ります。

あなたはまだあなたのforループが、ちょうど追加別。使用することができますので、それは私がこれを言うとき、私はRubyのマスターだふりをしていないfor i in 0...lst.length

+0

この答えはうまくいきますが、他の方法で問題を解決するにはRubyで' each 'を使用しないでください。ここで@Aetherusの答えがうまく解決されました。 – moveson

2

問題はlst[lst.length]は常にnilです。たとえば、lstが[1]の場合、lst[lst.length]lst[1]、つまりnilになります。

nilはオブジェクトであるため、メソッドを持つことができます。 nil > 0に電話すると、Rubyはそれをnil.>(0)と解釈します(>がメソッドであることが分かります)。 nilには方法>が含まれていないので、NoMethodErrorが得られます。

境界チェックの頭痛を取り除くには、forループを使わないでください。モジュールEnumerableから

def count_positives_sum_negatives(lst) 
    positives, negatives = lst.partition(&:positive?) 
    [positives.size, negatives.reduce(:+)] 
end 
両方 partition

reduceを来る:ここに私の実装です。私はnegativesグループに0を入れました。合計の結果には影響しないため、カウントの結果に影響します。

+1

OPのメソッドの名前は 'count_positives_sum_negatives'ですが、元のコードでは両方がカウントされます。それが意図ならば、このコードの3行目は '[positives.size、negatives.size]'に置き換えられます。あるいは、私たちは物事を数えているので、別名 '[positives.count、negatives.count]'を使うこともできます。 – moveson

+0

合意、@ moveson。私は質問にそれについてコメントし、私の答えでそれを言及し、新しい名前を示唆した。 –

+0

@movesonは名前の変更に同意しますが、 'count'は' size'のエイリアスではありません(ただし、 'size'は' length'のエイリアスです)。 'size'は実際には' count'よりはるかに高速です。 –

関連する問題