2017-01-01 3 views
2

Ich arbeite mit etwas langsamer Iteration, und würde gerne in der Lage sein, einen mehrfachen Schritt für diese Iteration anzugeben. Dies bedeutet, dass ich möchte, dass der Schritt zwischen a und b wechselt. Also, wenn ich hatte dies als eine Reihe (nicht faul nur zur Vereinfachung)Gibt es eine Möglichkeit, einen Mehrfachschritt in Ruby anzugeben?

(1..20).step(2, 4) 

ich mein resultierender Bereich

1 # + 2 = 
3 # + 4 = 
7 # + 2 = 
9 # + 4 = 
13 # + 2 = 
15 # + 4 = 
19 # + 2 = 21 (out of range, STOP ITERATION) 

wollen würde jedoch sein, ich kann nicht einen Weg finden, dies zu tun. Ist das in Ruby überhaupt möglich?

+0

Was sollte das erste Element sein? "1" oder "3"? Es ist '1' für' (1..20) .Schritt (2) 'das ist die Konvention, die ich für meine Antwort verwendet habe. –

Antwort

3

Sie eine Kombination aus cycle verwenden könnte und Enumerator:

class Range 
    def multi_step(*steps) 
    a = min 
    Enumerator.new do |yielder| 
     steps.cycle do |step| 
     yielder << a 
     a += step 
     break if a > max 
     end 
    end 
    end 
end 

p (1..20).multi_step(2, 4).to_a 
#=> [1, 3, 7, 9, 13, 15, 19] 

Beachten Sie, dass das erste Element 1 ist, weil das erste Element des (1..20).step(2) ist auch 1.

Es exclude_end? berücksichtigt:

p (1...19).multi_step(2, 4).to_a 
#=> [1, 3, 7, 9, 13, 15] 

Und kann faul sein:

p (0..2).multi_step(1,-1).first(20) 
#=> [0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1] 
p (0..Float::INFINITY).multi_step(*(1..100).to_a).lazy.map{|x| x*2}.first(20) 
#=> [0, 2, 6, 12, 20, 30, 42, 56, 72, 90, 110, 132, 156, 182, 210, 240, 272, 306, 342, 380] 

Hier ist eine Variante von FizzBuzz, die alle ein Vielfaches von 3 oder 5, aber nicht 15 erzeugt:

p (3..50).multi_step(2,1,3,1,2,6).to_a 
#=> [3, 5, 6, 9, 10, 12, 18, 20, 21, 24, 25, 27, 33, 35, 36, 39, 40, 42, 48, 50] 
+1

Ausgezeichnete Antwort! –

1

Rubin verfügt nicht über eine integrierte Methode für Schritt mit mehreren Werten. Wenn Sie jedoch keine faule Methode benötigen, können Sie Enumerable#cycle mit einem Akkumulator verwenden. Zum Beispiel:

range = 1..20 
accum = range.min 
[2, 4].cycle(range.max) { |step| accum += step; puts accum } 

Alternativ können Sie Ihre eigenen faul enumerator mit Enumerator::Lazy konstruieren. Das scheint für das angegebene Beispiel ein Overkill zu sein, kann aber nützlich sein, wenn Sie einen extrem großen Range object haben.

+1

Die Syntax sieht gut aus, aber der Parameter für http://ruby-doc.org/core-2.4.0/Enumerable.html#method-i-cycle ist die Anzahl der Wiederholungen der Enumerable, nicht der Bereich max . Ihr Beispiel iteriert von 3 bis 121. –

Verwandte Themen