Ok, quindi diciamo di avere una gamma davvero grande in rubino. Voglio trovare un modo per ottenere il valore massimo nell'intervallo.Il modo più veloce per ottenere il massimo valore da una gamma esclusiva in rubino
L'intervallo è esclusivo (definito con tre punti) che significa che non include l'oggetto finale nei risultati. Può essere costituito da Integer, String, Time o qualsiasi oggetto che risponda a #<=>
e #succ
. (Che sono gli unici requisiti per l'oggetto di inizio/fine in Range)
Ecco un esempio di una gamma esclusiva:
past = Time.local(2010, 1, 1, 0, 0, 0)
now = Time.now
range = past...now
range.include?(now) # => false
Ora so ho potuto solo fare qualcosa di simile per ottenere il valore massimo:
range.max # => returns 1 second before "now" using Enumerable#max
Ma questo richiederà una quantità non trascurabile di tempo per l'esecuzione. So anche che potrei sottrarre 1 secondo da qualunque sia l'oggetto finale. Tuttavia, l'oggetto potrebbe essere diverso da Time e potrebbe non supportare nemmeno #-
. Preferirei trovare una soluzione generale efficiente, ma sono disposto a combinare un codice caso speciale con una soluzione alternativa a una soluzione generale (ne parleremo più avanti).
Come accennato in precedenza utilizzando Range#last
non funzionerà neanche, perché è un intervallo esclusivo e non include l'ultimo valore nei suoi risultati.
L'approccio più veloce che potevo pensare era questo:
max = nil
range.each { |value| max = value }
# max now contains nil if the range is empty, or the max value
Questo è simile a quello che Enumerable#max
fa (che Gamma eredita), tranne che sfrutta il fatto che ogni valore sarà maggiore del precedente, quindi possiamo saltare usando #<=>
per confrontare ogni valore con il precedente (il modo in cui lo fa Range#max
) risparmiando un po 'di tempo.
L'altro approccio a cui stavo pensando era di avere un codice di caso speciale per tipi di ruby comuni come Integer, String, Time, Date, DateTime e quindi utilizzare il codice sopra come ripiego. Sarebbe un po 'brutto, ma probabilmente molto più efficiente quando si incontrano questi tipi di oggetto perché potrei usare la sottrazione da Range#last
per ottenere il valore massimo senza alcuna iterazione.
Qualcuno può pensare a un approccio più efficiente/più veloce di questo?
Nella tua ultima riga hai 'range.last.pred'. Questo non mi viene compilato. Neanche "range.last.prev'. Potresti spiegare per favore quella parte? –
Quindi prova a usare 'pred' e se fallisce, prova' range.last-1' altrimenti torna a una soluzione diversa –
'pred' è implementato per numeri interi nelle versioni successive di Ruby (è lì nel mio 1.8.7- 174, e dovrebbe essere lì in 1.9+). Non è disponibile per tutte le classi che implementano 'succ', quindi potrebbe essere necessario definirlo tu stesso. – molf