2013-05-26 9 views
5

Sto tentando di Problem 6 in Project Euler in Ruby (nel mio tentativo di imparare la lingua), e qui è quello che mi è venuta nella prima iterazione:Perché Ruby si lamenta di "metodo non definito` + 'per nil: NilClass (NoMethodError) "solo quando uso un condizionale' if '

upto = 10 
a = (1..upto).to_a.product((1..upto).to_a) 
#a.each{ |x| print "(#{x[0]}, #{x[1]})\n"} 
puts a.inject(0) {|sum, x| sum + x[0]*x[1] if (x[0] != x[1])} 

Purtroppo, che getta il seguente errore su Ruby 2.0:

in block in <main>': undefined method +' per nil: NilClass (NoMethodError)

Ancora più sconcertante è che l'errore non si verifica quando rimuovo il caso condizionale (che ovviamente mi dà la risposta sbagliata btw!)

upto = 10 
a = (1..upto).to_a.product((1..upto).to_a) 
a.each{ |x| print "(#{x[0]}, #{x[1]})\n"} 
puts a.inject(0) {|sum, x| sum + x[0]*x[1]} #if (x[0] != x[1])} 

Quanto sopra ha pronunciato la seguente uscita (dopo la stampa gli elementi di una):

Come passo il debug, ho anche stampato il contenuto della 'a', per garantire che non vi siano elementi nil - che si è rivelato soddisfacente. Qualcuno potrebbe spiegare

  1. Che cosa sto facendo di sbagliato qui?
  2. Perché la differenza quando escludo il condizionale "se", poiché il messaggio di errore è nell'operatore "+" che altrimenti viene eseguito incondizionatamente?

EDIT: Sarebbe anche bello ricevere commenti su modi alternativi, più eleganti per ottenere la stessa soluzione, come mi piacerebbe sapere il modo standard con cui un Rubyista risolverebbe questo!

+0

quale dovrebbe essere l'output del tuo codice? È '2640'? –

+0

@Priti: (1..upto)^2 - (1^2 + 2^2 ... fino a^2) – TCSGrad

+0

Non trovarti, ho un codice, voglio condividerti, basta confermarmi. '1^2 + 2^2 + 3^2 = 14'. Vuoi questa valutazione? –

risposta

2

Come sicuramente sapete, il valore di sum è qualunque sia il blocco valutati per l'espressione precedente (o il valore iniziale fornito la prima volta)

Che cosa il vostro codice dovrebbe fare è

if x[0] != x[1] 
    sum + x[0]*x[1] 
else 
    sum 
end 

il codice omette in modo efficace l'altro, in modo che quando la condizione non è soddisfatta, le vostre valutazioni di blocco a 0

si potrebbe anche voler sapere che

(1..upto).combination(2).to_a 

vi dà l'array di coppie non ripetuti direttamente in modo che non hai bisogno di tua if in Inject

Si potrebbe anche fare

(1..upto).to_a.combination(2).collect {|pair| 2* pair[0] * pair[1]}.inject(:+) 
+0

Ho cambiato la logica (dal momento che stiamo usando una combinazione, i termini aggiunti dovrebbero essere moltiplicati per 2, come stiamo ottenendo solo (x, y) e non (y, x)) - anche, devo aggiungere a_a prima della combinazione, altrimenti vedrò errori dal compilatore ... – TCSGrad

+0

Indipendentemente dalla modifica, una risposta stellare - grazie per aver segnalato combinazione! – TCSGrad

+0

Sembra che la mia modifica sia stata respinta - postando lo snippet di codice che fornisce la risposta corretta, nel caso l'OP/un editor voglia incorporarlo in modo che io possa accettare questa eccellente risposta come quella corretta: puts (1..upto) .to_a.combination (2) .Raccogliere {| x | 2 * x [0] * x [1]}. Inject (: +) – TCSGrad

4

Ecco perché si sta passando nil nel caso di x[0] != x[1] nel blocco di iniezione. Il valore di ritorno di questo blocco, è il nuovo valore del valore dell'accumulatore (sum), quindi, in assenza di modifiche, è sufficiente restituire sum. In caso contrario, il nuovo valore di sum è nil, per il quale nil.respond_to(:+) #=> false nella seguente iterazione, che porta all'errore che si è verificato.

n = 10 
a = (1..n).to_a.product((1..n).to_a) 
puts a.inject(0) {|sum, x| x[0] == x[1] ? sum + x[0] * x[1] : sum } 
2
puts a.inject(0) {|sum, x| sum + x[0]*x[1] if (x[0] != x[1])} 

nella dichiarazione Ruby al di sopra se la condizione (x [0]! = X [1]) è falsa la nil viene restituito per quel valore e viene salvato in 'somma' e quindi la prossima volta se la condizione si avvererà cercherà di aggiungere un po 'di valore per sommare e aggiungere qualche valore a nil solleverà questo errore.

prova a leggere questo documento.

http://ruby-doc.org/core-2.0/Enumerable.html#method-i-inject

Problemi correlati