2017-02-07 3 views
0

配列に数値を追加し、nil要素を無視します。私の解決策は明らかに機能しません。配列に数値を追加する際に、無限の要素を避けてください。

array = [3,4,5,6,nil,9,nil,9,3] 

def add(array) 
    array.inject(0){|memo,s|s.is_a?Integer ? memo+=s : next} 
end 
+0

'next'を使う代わりに' memo'を3者の最後の部分に返すだけです。また、injectでは、 'memo + = s'は' memo + s'と同じですので、ここで等号は実際には重複しています。 –

答えて

3

使用compact

array.compact.reduce(0,:+) 
+1

'reduce(0、:+)'を使用してください。そうでない場合、配列にゼロ以外の要素がない場合、 '0'ではなく' nil'を返します。 – Ursus

+0

ありがとうございます。私は配列に無限要素があると仮定していました –

+0

'(array- [nil])。inject(:+)' funのためだけに) –

0

私はそれを考え出した:

array.reject{|a| a.nil?}.inject(0){|memo,a| memo+=a} 
+1

それは動作は遅くなりますが、配列のサイズが大きくなるにつれてより遅くなります。 http://stackoverflow.com/a/42093625/128421で示されているように組み込みのメソッドを使用する方がよいでしょう。また、回答を選択しない限り、回答として「最終的な」コードを追加しない方がよいでしょう。 –

7

バージョンが動作しない理由は単純です:ブロックの戻り値はmemo値となり、次の反復のために。 sIntegerでない場合は、何も返さない、つまりnilなので、次の繰り返しではmemonilです。

あなたは、単にそのままメモを返すことでそれを修正することができます:

def add(array) 
    array.inject(0) { |memo, s| s.is_a? Integer ? memo += s : next memo } 
    #                ↑↑↑↑ 
end 

これはあなたの問題を解決します可能な最小の変更です。

nextが実際には必要ではないので、ブロックは通常、ブロック内で最後に評価された式の値を返します。

def add(array) 
    array.inject(0) { |memo, s| s.is_a? Integer ? memo += s : memo } 
end 

それはmemoに割り当てる意味がありません、それはスコープの外に出ますとにかくブロックの終わりに、あなたは再びそれを使用することはありません:

def add(array) 
    array.inject(0) { |memo, s| s.is_a? Integer ? memo + s : memo } 
end 

標準コミュニティスタイルガイドによると、引数リストのメッセージに送信し、それは「手続きのような」MESでない限り、括弧で囲む必要がありますセージ送信(例: putsrequire)または "キーワードのような" 一(例えばattr_accessor):

def add(array) 
    array.inject(0) { |memo, s| s.is_a?(Integer) ? memo + s : memo } 
end 

が個人的に、私は、条件演算子が好きではありません。それはしかし、文体の問題だが、私はずっとこれを好む:あなたが反復する前に

def add(array) 
    array.inject(0) { |memo, s| if s.is_a?(Integer) then memo + s else memo end } 
end 

しかし、はるかに簡単に解決策はnilの要素を削除することです:

よりエレガントに使って書くことができ
def add(array) 
    array.reject {|s| s.nil? }.inject(0) { |memo, s| memo + s } 
end 

Symbol#to_proc

def add(array) 
    array.reject(&:nil?).inject(0) { |memo, s| memo + s } 
end 

しかし、実際にはより読みやすいとちょうど同じです。

def add(array) 
    array.compact.inject(0) { |memo, s| memo + s } 
end 

あなたがSymbolとして組み合わせる方法の名前を渡すことができます:

def add(array) 
    array.compact.inject(0, :+) 
end 

そして、それはちょうど同じsumの通りです:あなたはそれを行うことができます

def add(array) 
    array.compact.sum 
end 
+0

それは誰も怠け者と呼ぶことのできない人です –

1

多くの方法:

array = [3,4,5,6,nil,9,nil,9,3] 
array.sum(&:to_i) # => 39 
array.reject(&:nil?).sum # => 39 

あなたがcompact代わりのreject(&:nil?)使用することができます。

array.compact.sum # => 39 

、あなたが合理的に最近のRubyを使用している必要がある場合は利用可能sumを、持っていない場合は、inject(:+)使用することができます。

array.compact.inject(:+) # => 39 

require 'fruity' 

compare do 
    sum_to_i { array.sum(&:to_i) } 
    reject_nil { array.reject(&:nil?).sum } 
    compact_reduce { array.compact.reduce(0,:+) } 
    compact_sum { array.compact.sum } 
    compact_inject { array.compact.inject(:+) } 
    do_not_do_this { array.reject{|a| a.nil?}.inject(0){|memo,a| memo+=a} } 
end 

# >> Running each test 8192 times. Test will take about 1 second. 
# >> compact_sum is faster than compact_inject by 10.000000000000009% ± 10.0% 
# >> compact_inject is similar to compact_reduce 
# >> compact_reduce is faster than sum_to_i by 19.999999999999996% ± 10.0% 
# >> sum_to_i is faster than reject_nil by 1.9x ± 0.1 
# >> reject_nil is faster than do_not_do_this by 2.0x ± 0.1 

Jörg's solutionは明らかに最も高速です。

関連する問題