I would really appreciate it if I could get some help on some questions regarding an assignment that prints out the data typed in by a user(In this specific example, the year, model, and make of the car):
# DEFINE YOUR CAR CLASS HERE
# create empty array
array_of_cars = Array.new
# prompt for and get number of cars
print "How many cars do you want to create? "
num_cars = gets.to_i
# create that many cars
for i in 1..num_cars
# get the make, model, and year
puts
print "Enter make for car #{i}: "
make = gets.chomp
print "Enter model for car #{i}: "
model = gets.chomp
print "Enter year of car #{i}: "
year = gets.to_i
# create a new Car object
c = Car.new
# set the make, model, and year
# that we just read in
c.set_make(make)
c.set_model(model)
c.set_year(year)
# add the Car object to the array
array_of_cars << c
end
# print out the information for
# the Car objects in the array
puts
puts "You have the following cars: "
for car in array_of_cars
puts "#{car.get_year} #{car.get_make} #{car.get_model}"
end
I already have some part of the program, but struggle with the main portion of it, since I kind of know what to do but not how to implement it.
So for this part: # DEFINE YOUR CAR CLASS HERE
I got this:
class Car
def assign(m,n,y)
#instance variables
#make = m
#model = n
#year = y
end
#instance methods
def set_make
end
def set_model
end
def set_year
end
def get_make
end
def get_model
end
def get_year
end
First, did I do it right with the instance variables?
And then, the purpose of "set" is to save the value into the array right? and then "get" allows me to extract them later. I think I would understand the concept if someone could show me how to define one of them.
I know that this seems a bit vague, so I will try my best to clarify if some questions occur. Also sorry for the wall of text and thank you!
In the first place, in “idiomatic ruby” we call getters and setters for #variable as variable (getter) and variable= (setter.) The constructor is to be named initialize, not assign.
There is a helper to define both for the class, Module#attr_accessor that declares both getter and setter under the hood, so that your class definition might be as short as:
class Car
attr_accessor :make, :model, :year
def initialize(make, model, year)
#make = make
#model = model
#year = year
end
end
So far so good. The rest of your code would be:
array_of_cars = [] # use Array.new with parameter, [] otherwise
# prompt for and get number of cars
print "How many cars do you want to create? "
num_cars = gets.to_i
# create that many cars
(1..num_cars).each do |i| # in idiomatic ruby, never use for loops
# get the make, model, and year
puts "Enter make for car #{i}: "
make = gets.chomp
print "Enter model for car #{i}: "
model = gets.chomp
print "Enter year of car #{i}: "
year = gets.to_i
# create a new Car object
c = Car.new(make, model, year)
# add the Car object to the array
array_of_cars << c
end
# print out the information for
# the Car objects in the array
puts
puts "You have the following cars: "
array_of_cars.each do |car|
puts "#{car.year} #{car.make} #{car.model}"
end
BTW, instead of pre-creating an array, one might better use Enumerable#map:
# prompt for and get number of cars
print "How many cars do you want to create? "
num_cars = gets.to_i
# ⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓⇓ DECLARE IT IN-PLACE
array_of_cars = (1..num_cars).map do |i|
puts "Enter make for car #{i}: "
make = gets.chomp
print "Enter model for car #{i}: "
model = gets.chomp
print "Enter year of car #{i}: "
year = gets.to_i
# create a new Car object
Car.new(make, model, year)
end
That would produce an array needed out of the box.
Addendum: to define getter and setter manually:
class Car
attr_accessor :make, :model
def initialize(make, model, year)
#make = make
#model = model
#year = year
end
# manually declare getter for year:
def year
#year
end
# manually declare setter for year:
def year=(year)
#year = year
end
end
Related
I am creating a program which creates a record for a Dog, that has the attributes (id, breed year born, and name). I have to use arrays to store the attributes of 3 dogs and then print them to the terminal.
require './input_functions'
class Dog
attr_accessor :id, :breed, :year_born, :name
def initialise (id, breed, year_born, name)
#id = id
#breed = breed
#year_born = year_born
#name = name
end
end
# Complete the missing code below
# Note: If your tasks requires outputting a floating point number you may wish to use the following:
# print out my_variable with 2 decimal places:
# printf("$%.2f\n", my_variable)
def read_dog()
puts "Enter the ID of your dog"
$dog_id = gets.to_s
puts "Enter the Breed of your dog"
$dog_breed = gets.to_s
puts "Enter the birth year of your dog"
$dog_year_born = gets.to_s
puts "Enter the name of your dog"
$dog_name = gets.to_s
end
def display_dog
puts $dog_id + "The dog ID is an Integer which is unique to your dog"
puts $dog_breed + "The dog breed is a String which defines the ancestors of your dog"
puts $dog_year_born + "The year born is an Integer which contains what year your dog was born"
puts $dog_name + "The dog name is a String which contains what your dog's name is"
end
def read_dogs
dogs = Array.new
index = 0
while (index < 3)
dogs << read_dog[index]
index = index + 1
end
return dogs
end
def display_dogs(dogs)
index = 0
while (index < 3)
dogs[display_dog.to_i]
index = index + 1
end
end
def main
dogs = read_dogs
display_dogs(dogs)
end
main
The expected result is that the program displays all entered information back to the user. What happens instead is that only the last set of data that is entered is shown three times. It obviously has something to do with how I am storing or extracting the data from the array but I can't figure out what that is.
First of all you must return some value from read_dog method
def read_dog()
puts "Enter the ID of your dog"
$dog_id = gets.to_s
puts "Enter the Breed of your dog"
$dog_breed = gets.to_s
puts "Enter the birth year of your dog"
$dog_year_born = gets.to_s
puts "Enter the name of your dog"
$dog_name = gets.to_s
return [$dog_id, $dog_breed, $dog_year_born, $dog_name]
end
Let me update you on other things as it only printing last information
Btw I am not seeing any use of Dog class code in your snippet at the moment
class Dog
attr_accessor :id, :breed, :year_born, :name
def self.ask_for_dogs(n_times)
all_dogs = []
n_times.times do
all_dogs << new
end
all_dogs
end
def self.display(dogs)
dogs.each do |dog|
puts "Id: #{dog.id}"
puts "Name: #{dog.name}"
puts "Breed: #{dog.breed}"
puts "Year born: #{dog.year_born}\n"
end
end
private
def initialize
puts "Enter the dog's ID:"
#id = gets.to_s
puts "Enter the dog's breed:"
#breed = gets.to_s
puts "Enter the dog's birth year:"
#year_born = gets.to_s
puts "Enter the dog's name:"
#name = gets.to_s
end
end
Run it, by defining the number of dogs you want to create.
In the loop dog objects are created, which are then printed out by the diplay method all at once, by accessing the attributes of the dog object.
dogs = Dog.ask_for_dogs(3)
Dog.display(dogs)
I'm writing a short program that asks a user to enter a car model, maker, and year input and it passes that input through an algorithm. My question is, is there a way to label multiple printed outputs after it has been put through the formula to where it will number each output? Would I have to use a for each loop? I'm just trying to get a general idea of how I would accomplish this.
say for example the printed output would look like this.
class Car
attr_reader :make, :model, :year
def initialize
end
def set_make(make)
#make = make
end
def set_model(model)
#model = model
end
def set_year(year)
#year = year
end
def get_make
#make
end
def get_year
#year
end
def get_model
#model
end
end
array_of_cars = Array.new
print "How many cars do you want to create? "
num_cars = gets.to_i
for i in 1..num_cars
puts
print "Enter make for car #{i}: "
make = gets.chomp
print "Enter model for car #{i}: "
model = gets.chomp
print "Enter year of car #{i}: "
year = gets.to_i
c = Car.new
c.set_make(make)
c.set_model(model)
c.set_year(year)
array_of_cars << c
end
puts
puts "You have the following cars: "
puts
for car in array_of_cars
puts "#{car.get_year} #{car.get_make} #{car.get_model}"
end
puts
2014 Ford Expedition
2017 Toyota 86
2017 Aston Martin DB11
is there a way to add those numbers to the output?
Instead using a for loop you could try using each_with_index, which will allow you to get each element inside the array_of_cars and also the index for each element, in this case adding 1 to the current index will give you the value starting from 1:
array_of_cars.each_with_index do |car, index|
puts "#{index + 1}. #{car.get_year} #{car.get_make} #{car.get_model}"
end
Or you can use each and with_index passing the first element, in this case 1 as argument:
array_of_cars.each.with_index(1) do |car, index|
puts "#{index}. #{car.get_year} #{car.get_make} #{car.get_model}"
end
You don't need so many methods. Use attr_accessor to set getters and setters and utilize initialize better. Then using the basic idea from this answer by tadman, we can collect newly made objects into an array within the class itself. All together we can compress your class to:
class Car
attr_accessor :make, :model, :year
def self.all
#all ||= []
end
def initialize(make, model, year)
#make = make
#model = model
#year = year
Car.all << self
end
end
We can use times to run a piece of code n times.
puts "How many cars do you want to create? "
n = gets.to_i
n.times.with_index(1) { |_,i|
puts "Enter make for car #{i}"
make = gets.chomp
puts "Enter model for car #{i}: "
model = gets.chomp
puts "Enter year of car #{i}: "
year = gets.to_i
puts
Car.new(make, model, year)
}
Then as Sebastián Palma has already suggested, use each.with_index(1) to print your cars. The argument offsets the index by 1.
Car.all.each.with_index(1) { |c, i| puts "#{i}. #{c.year} #{c.make} #{c.make}" }
Sidenotes: 1. Avoid using for loops in Ruby 2. Use puts not print.
I am looking at this code:
class Student
attr_accessor :first_name, :last_name, :age
def initialize(first, last, age)
#first_name = first
#last_name = last
#age = age
end
def birthday
#age += 1
end
end
class ViewStudent
def initialize(student)
#student = student
end
def do_something
puts "Student name: #{#student.first_name} #{#student.last_name}"
end
end
class UpdateStudent
def initialize(student)
#student = student
end
def do_something
puts "What is the student's first name?"
#student.first_name = gets.chomp
puts "What is the student's last name?"
#student.last_name = gets.chomp
puts "Updated student: #{#student.first_name} #{#student.last_name}"
end
end
choices = [ViewStudent, UpdateStudent]
student = Student.new("John", "Doe", 18)
puts "Select 1 to view student or 2 to update student."
selection = gets.chomp.to_i
obj = choices[selection - 1]
obj = obj.new(student)
obj.do_something
In the last five lines, I understand that selection = gets.chomp.to_i converts the selection options to integers, but how does that work in tandem with obj = choices[selection - 1]?
I'm also not sure what obj = obj.new(student) and obj.do_something do. It looks like a local variable is being set to create a new object with student as the argument. However, obj isn't a class or method to call on?
I can also gather that obj.do_something calls the methods defined for both ViewStudent and UpdateStudent given the selection.
I saw this, but it doesn't answer my question.
obj = choices[selection - 1] just select ViewStudent if 1 and UpdateStudent if 2 from your array by index (choices[0] or choices[1]).
Then you creating an instance of selected class (ViewStudent.new or UpdateStudent.new) and call do_something method on this instance, because this methos difined in both classes:
obj = choices[selection - 1] # obj is ViewStudent or UpdateStudent class
obj = obj.new(student) # obj is ViewStudent or UpdateStudent instance
obj.do_something # call `do something` method on instance
Hi I am a student learning Ruby. I am using the quick start guide at ruby-lang.org, which has some examples of Ruby basics.
I studied the MegaGreeter class, and I am trying to figure out how to puts two arguments (name and age) in the same each block in order to simplify my code.
I think there would be another way. (Using regular loops instead of each.)
Calculate the array's size.
Use a loop like in C.
But I want to use the each loop. Below is my code:
class MegaGreeter
attr_accessor :name
attr_accessor :age
#Creat the object
def initialize(name=nil, age=0)
#name = name
#age = age
#tmp = Array.new()
#i = 0
end
#Say hi to everybody
def say_hi
if #name.nil?
puts "please give me the input !!"
elsif #name.respond_to?("each")
#list responding
#name.each do |name|
#tmp[#i] = "hi ~! #{name}"
#i += 1
end
#i=0
#age.each do |age|
#tmp[#i] += " and you are #{age} years old"
puts #tmp[#i]
#i += 1
end
else
puts "give me array ~"
end
end
end
a = MegaGreeter.new()
a.name = ["juno","yoonhe"]
a.age = [1,2]
a.say_hi
You can use the Array method zip to first combine your two arrays. It groups the elements by their position in the array, so the first element of the #name array will be grouped with the first element of the #age array and so on.
#name = ['Foo', 'Bar']
#age = [23, 41]
name_and_age = #name.zip(#age)
# [['Foo', 23], ['Bar' 41]]
Now the names and ages are grouped together, and you can iterate over them using each.
name_and_age.each do |name, age|
puts name, age
end
# Foo 23
# Bar 41
Putting it back into your original code:
class MegaGreeter
attr_accessor :name, :age
#Creat the object
def initialize(name = nil, age = 0)
#name = name
#age = age
end
#Say hi to everybody
def say_hi
if #name.nil?
puts "please give me the input !!"
elsif #name.respond_to?("each")
#list responding
#name.zip(#age).each do |name, age|
puts "hi ~! #{name} and you are #{age} years old"
end
else
puts "give me array ~"
end
end
end
I would like users to be able to dynamically create objects of the Incomes class below. That is, I would like to fire my program and let users enter as many incomes as they like, all stored as instances of the Incomes class.
def prompt
puts "> "
end
class Incomes
def initialize(aName, aAmount, aCOLA)
#name = aName
#amount = aAmount
#COLA = aCOLA
end
end
def addIncome
puts "What is the company name?"
prompt
aName = gets.chomp
puts "What is the monthly amount?"
aAmount = gets.chomp
puts "What is the cost of living adjustment?"
aCOLA = gets.chomp
end
#Now I want to be able to loop back through addIncome and create as many objects as the
#user wants. Perhaps there's a better way to store this type of data?
def prompt question
print "#{question} > "
gets
end
class Incomes
attr_reader :name, :amount, :COLA
##instances_of_Incomes = Array.new
def initialize(aName, aAmount, aCOLA)
#name = aName
#amount = aAmount
#COLA = aCOLA
#instances_of_Incomes = Array.new
end
def self.addIncome
name = prompt "What is the company name?"
amount = prompt "What is the monthly amount?"
_COLA = prompt "What is the cost of living adjustment?"
##instances_of_Incomes << Incomes.new(name, amount, _COLA)
end
def self.instances
##instances_of_Incomes
end
end
5.times do
Incomes.addIncome
end
puts Incomes.instances
Incomes.instances.each do |company|
puts company.name
end
I have refactored the code to show that you can use inputs to create the instances. They are unnamed classes, but stored in a class variable.
I also show that you can extract the name of each Incomes instance.
I have also edited your SE Code Review question, with the same code, so hopefully you can get some good reviews.