Joel Davison
Joel Davison

Reputation: 43

Creating a class object inside a loop

I think my question is pretty simple but I'm not flash on the fundamentals.

I have a class and I want to store data in it from a loop and access those class objects outside of the loop. For example, I want code like below

class Numbers
  attr_accessor :value

end

n = 1

while n < 10
  p = Numbers.new
  p.value = n
  n += 1
  puts p.value
end

but instead of iterating over each Number made inside of the loop, I want to store each class object and iterate over the collection outside of the initial loop. In my mind the code looks like this, but it's clearly not the right way to go about it.

class Numbers
  attr_accessor :value
end

n = 1

while n < 10
  Numbers.new
  Numbers.value = n
  n += 1
end

Numbers.each do |f|
  puts f.value
end

I ask because I want to apply this technique to a more complex problem, thank you in advance for any help you can give.

Upvotes: 4

Views: 2279

Answers (3)

Lukas Baliak
Lukas Baliak

Reputation: 2869

You can use ˙class variable˙ like collector for instances.

class Number
  attr_accessor :value
  @@numbers = []

  def initialize(value = nil)
    @value = value
    @@numbers << self
  end

  def self.each
    @@numbers.each do |inst|
      yield inst
    end
  end
end

And then use

1.upto(9){|n| Number.new(n)}

Number.each{|inst| puts inst.value}
# => 1
# => 2
# => 3
# => 4
# => 5
# => 6
# => 7
# => 8
# => 9

Upvotes: 0

Eric Duminil
Eric Duminil

Reputation: 54223

Refactoring

Since your Number value probably shouldn't be changed, you could just set value when you create the Number object :

class Number
  attr_reader :value
  def initialize(value)
    @value = value
  end

  def to_s
    @value.to_s
  end
end

numbers = Array.new(10) { |i| Number.new(i) }

puts numbers
# => 
# 0
# 1
# 2
# 3
# 4
# 5
# 6
# 7
# 8
# 9

Range

If you want Numbers between 1 and 9 :

numbers = (1..9).map { |i| Number.new(i) }

puts number

to_s method has been defined in order to avoid getting :

#<Number:0x00000001363a70>
#<Number:0x00000001363a48>
#<Number:0x00000001363a20>
#<Number:0x000000013639f8>
#<Number:0x000000013639d0>
#<Number:0x000000013639a8>
#<Number:0x00000001363980>
#<Number:0x00000001363958>
#<Number:0x00000001363930>

when using puts

Basic arithmetic

For basic arithmetic, you could add this method :

def +(other)
  self.class.new(value + other.value)
end

to Number.

Now you can type :

puts Number.new(1) + Number.new(2)
#=> 3

Upvotes: 1

akuhn
akuhn

Reputation: 27793

Try this

class Number
  attr_accessor :value
end

numbers = (1..9).map do |n| 
  number = Number.new
  number.value = n
  number
end

How does this work?

  • map is a loop that creates an array with the result from each iteration
  • (1..9).map { |n| ... } hence creates an array of 9 number objects

I guess you are new to Ruby so here is some help with classes and objects

  • Number is a class
  • number is an object
  • Number.new creates an object that is an instance of class Number
  • value is defined by Number class and thus available on instances of that class
  • number.value is thus valid
  • Number.value is thus invalid and does not make sense
  • Use an array to store many objects

So your text should thus say

"I have a class and I want to create instances of it from a loop and access these instances outside of the loop. [...] But instead of iterating over each object made inside of the loop, I want to store each instance in an array and iterate over the array outside of the initial loop."

Upvotes: 4

Related Questions