2010-07-29 14 views
8

Diciamo che ho un range da 0 a 10:Esiste un modo elegante per escludere il primo valore di un intervallo?

range = 0...10 

Tre punti significano, che l'ultimo valore (10) è esclusa:

range.include? 10 
=> false 

Ora, c'è un modo simile ed elegante escludere il valore prima?
Per l'esempio precedente, questo significherebbe per includere tutti i valori che sono più grandi (>, non>=) di 0 e minore di 10.

+0

Penso che escludere l'ultimo valore sia spesso abbastanza utile come "intervallo = 0 ... qualcosa. Dimensione" Qual è il tuo caso per aver bisogno di escludere il valore _primo? –

+0

Controllo se un determinato insieme di valori si trova all'interno di quell'intervallo. Voglio solo gestire i valori zero in modo diverso. So come ottenere ciò, ma ero curioso, se c'è qualcosa di simile come '...' per escludere il * primo * valore di un intervallo. –

+0

Ho imparato di più sull'intervallo in 5 minuti rispetto all'anno scorso. Grazie! –

risposta

2

No.

((0+1)..10) 
+3

L'unico problema con questo sarebbe, che i valori tra 0 e 1 non sarebbero inclusi. Sì, puoi dire '0.00000001..10' (o qualcosa di simile, a seconda di quanti decimali ti servono). Ma è piuttosto brutto, IMO, quando la cosa che voglio dire è: '0

+4

Da Ruby 2.2 puoi usare '(0.0) .next_float..10.0' – Envek

+0

Oppure, la mia sintassi preferita:' 0.to_f.next_float..10' – Danyel

0

Forse potresti creare il tuo tipo di intervallo.

5

Ho due suggerimenti per te, non sono molto ideali ma sono il meglio che riesco a pensare.

Per prima cosa è possibile definire un nuovo metodo nella classe Range che esegue ciò che viene descritto. Sarebbe simile a questa:

class Range 
    def have?(x) 
    if x == self.begin 
     false 
    else 
     include?(x) 
    end 
    end 
end 

p (0..10).have?(0)  #=> false 
p (0..10).have?(0.00001) #=> true 

Non lo so, ho solo usato un sinonimo di "includere" come nome del metodo, forse si può pensare a qualcosa di meglio. Ma questa è l'idea.

E quindi si potrebbe fare qualcosa di un po 'più elaborato e definire un metodo sulla classe Range che contrassegna un intervallo come si desidera escludere il valore iniziale di e quindi modificare il metodo include? di Range per verificare quel segno.

class Range 
    def exclude_begin 
    @exclude_begin = true 
    self 
    end 

    alias_method :original_include?, :include? 
    def include?(x) 
    return false if x == self.begin && instance_variable_defined?(:@exclude_begin) 
    original_include?(x) 
    end 

    alias_method :===, :include? 
    alias_method :member?, :include? 
end 

p (0..10).include?(0)      #=> true 
p (0..10).include?(0.00001)    #=> true 
p (0..10).exclude_begin.include?(0)  #=> false 
p (0..10).exclude_begin.include?(0.00001) #=> true 

Anche in questo caso, si consiglia una migliore (più elegante?) Nome per il metodo di exclude_begin, ho solo scelto che dal momento che è in linea con il metodo di intervallo exclude_end?.

Modifica: Ne ho un altro per te, solo perché trovo questo problema così interessante. : P Questo sarà il lavoro solo nella più recente versione di Ruby 1.9, ma consentirà la seguente sintassi:

(0.exclude..10).include? 0  #=> false 
(0.exclude..10).include? 0.00001 #=> true 

Esso utilizza la stessa idea come il mio secondo suggerimento, ma memorizza il "marcatore di esclusione" nel numero invece della gamma. Devo usare SimpleDelegator di Ruby 1.9 per fare ciò (i numeri da soli non possono avere variabili di istanza o altro), motivo per cui non funzionerà nelle versioni precedenti di Ruby.

require "delegate" 

class Numeric 
    def exclude 
    o = SimpleDelegator.new(self) 
    def o.exclude_this?() true end 
    o 
    end 
end 

class Range 
    alias_method :original_include?, :include? 
    def include?(x) 
    return false if x == self.begin && 
        self.begin.respond_to?(:exclude_this?) && 
        self.begin.exclude_this? 
    original_include?(x) 
    end 

    alias_method :===, :include? 
    alias_method :member?, :include? 
end 
+0

Wow. Questa è un'ottima risposta. Molte grazie! Sono ancora impegnato a cercare di capire la tua soluzione Ruby 1.9. È bello vedere cosa è possibile. Tuttavia, ritengo che la soluzione più elegante e più ovvia IMO sarebbe quella di descrivere un intervallo escludendo i valori iniziali e finali di quattro punti: '0 .... 10'. Non sono davvero sicuro se questo è possibile anche senza fare casino con il file range.c !? –

+0

Sì, sono d'accordo che sarebbe una bella sintassi, ma richiederebbe una modifica alla grammatica di Ruby (causa un errore di sintassi se la digiti dentro). Una cosa che puoi fare in questo modo in Ruby 1.9 è usare il mio ultimo esempio, ma chiama il metodo 'call' invece di' exclude'. Quindi puoi usare il nuovo zucchero di sintassi di Ruby e scrivere '0.() .. 10' e ottenere la stessa cosa. '0.()' È una scorciatoia per il metodo 'call'. Non so se sia meglio o no, comunque. : P –

+0

Sì, bello. Ma questo significherebbe una totale confusione, immagino. ;-) Preferisco attenermi alle tue soluzioni '(0..10) .exclude_begin' o' 0.exclude..10'. Grazie per la tua risposta di nuovo. Ho imparato molto. (Ho accettato un'altra risposta, perché non la descriverei come una soluzione elegante simile alla notazione a tre punti per escludere l'ultimo valore). –

Problemi correlati