Damir Nurgaliev
Damir Nurgaliev

Reputation: 351

How to correctly write a ruby method

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

Answers (2)

Andrey Deineko
Andrey Deineko

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

edit

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

steenslag
steenslag

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

Related Questions