Reputation: 351
i'm trying ruby. I want to make a program which can continue the sequence.
1
11
21
1211
111221
(which next line is a calculated each number of previous line) For example last line is(see previous) one of 1, one of 2, and two of 1. I make a code and it works fine:
5.times do
result_seq = []
count = 1
puts initial_seq.join
initial_seq.size.times do
if (value = initial_seq.shift) == initial_seq.first
count += 1
else
result_seq << count << value
count = 1
end
end
initial_seq = result_seq
end
But now I want to write a simple method called Next
I want to make:
sec = Sequence.new(1)
sec.next -> will return 11
sec.next.next -> will return 21
sec.next.next.next -> will return 1211
How can i write it correctly using my code?
UPD
I wrote the tests for it:
require "spec_helper"
require "sequence"
describe Sequence do
let(:sequence) { Sequence.new("1") }
describe "to_s" do
it "return initial value" do
expect(sequence.to_s).to eql "1"
end
end
describe "next" do
it "generate next state" do
expect(sequence.next.to_s).to eql "11"
end
it "return Sequence instance" do
expect(sequence.next).to be_an_instance_of(Sequence)
end
it "generate next state 2 times" do
expect(sequence.next.next.to_s).to eql "21"
end
it "generate next state 3 times" do
expect(sequence.next.next.next.to_s).to eql "1211"
end
end
end
Upvotes: 0
Views: 51
Reputation: 52347
class Sequence
attr_reader :initial_seq
def initialize(initial_seq = [])
@initial_seq = initial_seq
print_next
end
def print_next
result_seq = []
count = 1
puts initial_seq.join
initial_seq.size.times do
if (value = initial_seq.shift) == initial_seq.first
count += 1
else
result_seq << count << value
count = 1
end
end
@initial_seq = result_seq
self #<===== The most important part for being able to chain `print_next`
end
end
Usage:
Sequence.new([1]).print_next.print_next.print_next.print_next
1
11
21
1211
111221
If you want to initialize it with integer argument, not array:
def initialize(number)
@initial_seq = [number]
print_next
end
Sequence.new(1).print_next.print_next
1
11
21
Or, if you do not want initialize
to accept an argument (assuming, it will always start with 1
):
def initialize
@initial_seq = [1]
print_next
end
Sequence.new.print_next.print_next
1
11
21
Upvotes: 2
Reputation: 80065
Ruby provides Enumerators, which behave almost like in OP. Leaving the original code almost unaltered:
seq = Enumerator.new do |yielder|
initial_seq = [1]
loop do #endless loop, but don't worry, its lazy
result_seq = []
count = 1
yielder << initial_seq.join
initial_seq.size.times do
if (value = initial_seq.shift) == initial_seq.first
count += 1
else
result_seq << count << value
count = 1
end
end
initial_seq = result_seq
end
end
5.times{puts seq.next}
puts seq.next
Upvotes: 2