2010-07-29 4 views
8

Lassen Sie uns sagen, dass ich einen Bereich von 0 bis 10 haben:Gibt es eine elegante Möglichkeit, den ersten Wert eines Bereichs auszuschließen?

range = 0...10 

Drei Punkte bedeuten, dass der letzte Wert (10) ausgeschlossen ist:

range.include? 10 
=> false 

Nun gibt es eine ähnliche und elegante Art und Weise um den ersten Wert auszuschließen?
Für das obige Beispiel würde dies bedeuten, daß alle Werte enthalten, die größer (>, nicht>=) als 0 und kleiner als 10.

+0

Ich denke, dass das Ausschließen des letzten Werts oft ziemlich nützlich ist, wie 'range = 0 ... something.size' Was ist Ihr Anwendungsfall, den _first_ Wert ausschließen zu müssen? –

+0

Ich überprüfe, ob ein bestimmter Satz von Werten in diesem Bereich liegt. Ich möchte nur Nullwerte anders behandeln. Ich weiß, wie man das erreicht, aber ich war neugierig, ob es etwas ähnliches wie '...' gibt, um den * ersten * Wert eines Bereichs auszuschließen. –

+0

Ich habe in 5 Minuten mehr über die Reichweite erfahren als im letzten Jahr. Vielen Dank! –

Antwort

2

Nr

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

Das einzige Problem dabei wäre, dass Werte zwischen 0 und 1 nicht enthalten wären. Ja, Sie können '0.00000001..10' (oder etwas Ähnliches sagen, abhängig davon, wie viele Dezimalstellen Sie benötigen). Aber das ist ziemlich hässlich, IMO, wenn das, was ich sagen möchte, ist: 0

+4

Seit Ruby 2.2 können Sie '(0.0) .next_float..10.0' verwenden – Envek

+0

Oder meine bevorzugte Syntax:' 0.to_f.next_float..10' – Danyel

0

Vielleicht sind Sie könnten Ihren eigenen Bereichstyp erstellen.

class FancyRange 
    def initialize(minimum, maximum, exclusive_minimum, exclusive_maximum) 
    # insert code here 
    end 

    # insert more code here 

end 
5

Ich habe zwei Vorschläge für Sie, sind sie nicht sehr ideal, aber sie sind das Beste, was ich mir vorstellen kann.

Zuerst können Sie eine neue Methode für die Range-Klasse definieren, die das ausführt, was Sie beschreiben. Es würde wie folgt aussehen:

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 

Ich weiß nicht, habe ich nur ein Synonym für „include“ als Methode Namen, vielleicht können Sie besser etwas denken. Aber das ist die Idee.

Und dann könnten Sie etwas aufwendigeres tun, und definieren Sie eine Methode für die Range-Klasse, die einen Bereich als eine, die Sie den Anfangswert von ausschließen möchten, und ändern Sie dann Bereich include? Methode, um nach dieser Marke zu überprüfen.

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 

Auch hier können Sie ein besseres wollen (elegantere?) Namen für die Methode als exclude_begin, entschied ich mich nur, dass da es im Einklang mit der Reichweite exclude_end? Methode.

Bearbeiten: Ich habe eine andere für Sie, nur weil ich dieses Problem so interessant finde. : P Dies wird funktionieren nur in der neuesten Version von Ruby 1.9, aber die folgende Syntax erlauben:

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

Es nutzt die gleiche Idee wie mein zweiter Vorschlag, aber speichert den „Ausschluss-Marker“ in der Zahl anstelle der Reichweite. Ich muss den SimpleDelegator von Ruby 1.9 verwenden, um dies zu erreichen (Zahlen allein können keine Instanzvariablen haben oder irgendetwas), weshalb es in früheren Versionen von Ruby nicht funktioniert.

+0

Wow. Das ist eine großartige Antwort. Danke vielmals! Ich bin immer noch damit beschäftigt, Ihre Ruby 1.9-Lösung zu verstehen. Es ist schön zu sehen, was möglich ist. Ich denke jedoch, dass die eleganteste und offensichtlichste Lösung IMO darin besteht, einen Bereich mit ausschließlich Anfangs- und Endwerten durch vier Punkte zu beschreiben: "0 .... 10". Ich bin mir wirklich nicht sicher, ob das überhaupt möglich ist, ohne mit der range.c-Datei herumzuspielen !? –

+0

Ja, ich stimme zu, dass das eine nette Syntax wäre, aber es würde eine Änderung der Ruby-Grammatik erfordern (es verursacht einen Syntaxfehler, wenn du es eingibst). Eine Sache, die Sie in Ruby 1.9 tun können, ist, dass Sie dort mein letztes Beispiel verwenden, aber benennen Sie die Methode 'call' anstelle von' exclude'. Dann können Sie Rubys neue Syntax Zucker verwenden und '0.() .. 10 'schreiben und dasselbe erhalten. '0.()' Ist eine Abkürzung für die Methode 'call'. Ich weiß nicht, ob das besser ist oder nicht. : P –

+0

Ja, schön. Aber das würde totale Verwirrung bedeuten, denke ich. ;-) Ich bleibe lieber bei deinen '(0..10) .exclude_begin' oder' 0.exclude..10' Lösungen. Danke für deine Antwort. Ich habe viel gelernt. (Ich akzeptierte eine andere Antwort, weil ich dies nicht als eine elegante Lösung ähnlich der Drei-Punkt-Notation beschreiben würde, um den letzten Wert auszuschließen). –

Verwandte Themen