2012-11-09 9 views
18

Data:Rails: Trovare massimo di array che può contenere zero

shipping_costs = { 
    key1: 45, 
    key2: 99, 
    key3: nil, 
    key4: 24 
} 

Qual è il modo più pulito per ottenere il massimo di quelle chiavi assumendo nil = 0?

Se corro una scala shipping_costs.values.max nella console Rails ottengo questo:

ArgumentError: comparison of Fixnum with nil failed 

modo più pulito per trasformare quelle Nils in zeri prima di eseguire max?

risposta

25

mi piacerebbe andare per:

shipping_costs.values.map(&:to_i).max 

nil.to_i è 0.

+2

Più tecnicamente corretto e specifico per la domanda, in modo da ottenere la risposta. Probabilmente farò la soluzione di Tom però. :) –

+1

Qui c'è una potenziale fonte di bug, che restituisce un massimo di zero per l'array [nil, -2, -4, -1], quando presumibilmente vuoi -1. Per questo motivo preferirei la soluzione di @toniedzwiedz. – isthmuses

+0

La domanda ha specificato che i valori di 'nil' dovrebbero essere considerati' = 0'. – Shadwell

2

fare shipping_costs.values.reject {|v| v.nil? }.max

+1

'reject' è più pulito di un' select' combinato con un 'not'. 'compact' è più conciso, ma tutto questo fallisce quando tutti i fixnum sono negativi e nil è il massimo. – steenslag

+0

grazie. Sapevo che c'era qualcosa di simile ma non l'ho mai usato –

+0

@IsmaelAbreu compact non fallisce sui numeri negativi, rimuove solo i valori nulli e seleziona il negativo con il valore assoluto più basso. – toniedzwiedz

28

Se si desidera mantenere davvero concisa, è possibile utilizzare shipping_costs.values.compact.max

Il metodo rimuove tutti i compactnil i valori da una matrice.

Le altre risposte sono anche buone idee. Tuttavia, preferirei rifiutare i valori anziché sostituirli con i numeri. Penso che sia meglio sapere che un array contiene solo valori nil piuttosto che indovinare da dove proviene uno 0 (o qualunque valore tu scelga).

+0

Buona, risposta pulita! Dovrò controllare nulla se TUTTI i valori finiscono per essere nulli. '[] .max' => nil. –

+0

@JamonHolmgren Penso che sia meglio sapere che contiene solo valori 'nil' invece di indovinare da dove proviene un' 0';) – toniedzwiedz

+0

Sì, probabilmente hai ragione. –

5

max prende un blocco, che consente di fare un confronto, in modo simile a come sort opere:

[45, 99, nil, 24].max{ |a,b| (a || 0) <=> (b || 0) } 
=> 99 

o:

[45, 99, nil, 24].max{ |a,b| a.to_i <=> b.to_i } 
=> 99 

Ciò consente di forzare il valore come si desidera/bisogno, prima che avvenga il confronto.

Per il vostro caso, shipping_costs.values restituirà la matrice è necessario confrontare, in modo da:

shipping_costs.values.max{ |a,b| a.to_i <=> b.to_i } 
+0

Questo non funzionerà per un array che contiene solo valori negativi, nel caso in cui 'nil' sarà restituito come l'elemento massimo (' nil.to_i' restituisce 0). Tuttavia, in questo caso specifico, la matrice contiene * costi *, quindi è difficile aspettarsi un valore negativo. +1 – toniedzwiedz

6

Nessuno ha menzionato forma ancora più breve ?,

shipping_costs.values.max_by(&:to_i) 

(Solo un info)

Problemi correlati