Output display as null (Ruby) - arrays

Here when we print array elements it display null value all time like "[nil, nil, nil, nil]"
Values are not getting stored in array.
class Flight
def initilize(flight_id, flight_num, flight_orgin, flight_destination)
#id= flight_id
#number = flight_number
#origin = flight_origin
#destination = flight_destination
end
def read_flight()
puts "enter flight id"
flight_id = gets.chomp
puts "enter flight number"
flight_number = gets.chomp
puts "enter flight origin location"
flight_origin = gets.chomp
puts "enter destination"
flight_destination = gets.chomp
end
def print_flight(id, number, orgin, destination)
puts "_____Flight details______"
puts "Flight_id :#{id}"
puts "Flight_number :#{number}"
puts "Flight_orgin :#{orgin}"
puts "Flight_destination:#{destination}"
end
def read_flights(id, number, orgin, destination)
puts "_______Array of flights______"
flightid = Array.new
flightid.push(id, number, orgin, destination)
puts "#{flightid}"
end
end
input_flight = Flight.new
input_flight.read_flight
input_flight.print_flight(#id, #num, #orgin, #destination)
input_flight.read_flights(#id, #num, #orgin, #destination)
Without using a class or instance variable we want to do it
User input
enter flight id
2
enter flight number
2342
enter flight origin location
cochin
enter destination
tvm
output
Flight details_
Flight_id :
Flight_number :
Flight_orgin :
Flight_destination:
_Array of flights
[nil, nil, nil, nil]

The #id, #num, #orgin, #destination parameters will be nil if you don't set them anywhere.
So when you make these two calls:
input_flight.print_flight(#id, #num, #orgin, #destination)
input_flight.read_flights(#id, #num, #orgin, #destination)
You basically just send nils into the function:
input_flight.print_flight(nil, nil, nil, nil)
input_flight.read_flights(nil, nil, nil, nil)
If you want to access the variables read from the input:
First, you need to store them somewhere. For ex: store them inside the instance variables when read_flight function is called.
Then, refer the instance variable when you want to push values in the array.
Ex:
def read_flight
puts "enter flight id"
#id = gets.chomp # store inside instance variable
puts "enter flight number"
#number = gets.chomp
puts "enter flight origin location"
#origin = gets.chomp
puts "enter destination"
#destination = gets.chomp
end
def read_flights
...
flightid.push(#id, #number, #origin, #destination) # access instance variables here
...
end
You can learn more about Ruby's variable scoping (instance variables, global variables, etc) here: https://www.techotopia.com/index.php/Ruby_Variable_Scope

Here is my version of adjustion:
class Flight
attr_reader :id, :number, :origin, :destination
def read_flight
puts "enter flight id"
#id = gets.chomp
puts "enter flight number"
#number = gets.chomp
puts "enter flight origin location"
#origin = gets.chomp
puts "enter destination"
#destination = gets.chomp
end
def print_flight
puts "_____Flight details______"
puts "Flight_id :#{id}"
puts "Flight_number :#{number}"
puts "Flight_orgin :#{origin}"
puts "Flight_destination:#{destination}"
end
def read_flights
puts "_______Array of flights______"
flightid = [id, number, origin, destination]
puts "#{flightid}"
end
end
input_flight = Flight.new
input_flight.read_flight
input_flight.print_flight
input_flight.read_flights
Explanation:
Each instance of ruby class can have as many instance variables (which begin with #) as possible. Those instance variables live in an instance so they keep their value across the methods.
So you should assign the value you want to instance variables, for example:
#id = gets.chomp
then use it in another method:
def print_flight
puts "_____Flight details______"
puts "Flight_id :#{#id}"
end
However, add # everytime we want to use the instance variables is pretty tedious. That's why attr_reader comes in. When you write attr_reader:
attr_reader :id, :number, :origin, :destination
You actually declare 4 methods inside Flight:
def id
#id
end
def number
#number
end
def origin
#origin
end
def destination
#destination
end
Then you can just use id, number, origin, destination without the leading #`

You're initializing with nil values in your constructor (def initialize), to fix that you can pass the values to the .new or change the read_flight as follows:
def read_flight()
puts "enter flight id"
#flight_id = gets.chomp
puts "enter flight number"
#flight_number = gets.chomp
puts "enter flight origin location"
#flight_origin = gets.chomp
puts "enter destination"
#flight_destination = gets.chomp
end
This will modify the class-scoped variables.
Or alternatively you can have default values in the constructor (not recommended) using the || operator:
def initilize(flight_id, flight_num, flight_orgin, flight_destination)
#id= flight_id || 0
#number = flight_number || 0
#origin = flight_origin || ""
#destination = flight_destination || ""
end

First of all, be careful, because you did a lot of little but important mistakes. It's ok, we all started like that)
For example, your 'initialize' method name is not correct!
Your: 'initilize'
Correct: 'initialize'
It's important to name default methods correct.
Also, when you initialize variables with method arguments:
def initilize(flight_id, flight_num, flight_orgin, flight_destination)
#id= flight_id
#number = flight_num #you have to name it just like argument in method not flight_number, because it does not exist at all
#origin = flight_origin #same here, you forgot one letter
#destination = flight_destination
end
If you want user to initialize your instances then don't initialize them by yourself, delete arguments in initialize method.
Also, you can use instance variables in entire class, it's really helpful!
So, i corrected a little:
class Flight
def read_flight
puts "enter flight id"
#id = gets.chomp
puts "enter flight number"
#number = gets.chomp
puts "enter flight origin location"
#origin = gets.chomp
puts "enter destination"
#destination = gets.chomp
end
def print_flight
puts "_____Flight details______"
puts "Flight_id : " + #id.to_s
puts "Flight_number : " + #number.to_s
puts "Flight_origin : " + #origin
puts "Flight_destination: " + #destination
end
def read_flights
puts "_______Array of flights______"
flightid = Array.new
flightid.push({ #id,#number,#origin,#destination })
puts "#{flightid}"
end
end
Check:
input_flight = Flight.new
input_flight.read_flight
input_flight.print_flight
input_flight.read_flights

Related

Ruby, how can i compare a string with a specific element of array?

I create an array from a text file which contains the english irregular verbs. I want the code to ask me the verbs in random order letting me proceed only if I respond correctly. I need to compare a string with an element of array. I wrote this:
a = []
File.open('documents/programmi_test/verbi.txt') do |f|
f.lines.each do |line|
a <<line.split.map(&:to_s)
end
end
puts ''
b = rand(3)
puts a[b][0]
puts 'infinitive'
infinitive = gets.chomp
if infinitive = a[b][1] #--> write like this, I receive alway "true"
puts 'simple past'
else
puts 'retry'
end
pastsimple = gets.chomp
if pastsimple == a[b][2] #--> write like this, I receive alway "false"
puts 'past participle'
else
puts 'retry'
end
pastpart = gets.chomp
if pastpart == a[b][3]
puts 'compliments'
else
puts 'oh, no'
end
can somebody help me?
if infinitive = a[b][1] is assigning to inifinitive the value of a[b][1], unlike pastsimple == a[b][2] that's a comparation between both values.
You could try replacing the = for ==.
a = []
File.open('documents/programmi_test/verbi.txt') do |file|
file.lines.each do |line|
a << line.split.map(&:to_s)
end
end
puts ''
b = rand(3)
puts a[b][0]
puts 'infinitive'
infinitive = gets.chomp
puts infinitive == a[b][1] ? 'simple past' : 'retry'
pastsimple = gets.chomp
puts pastsimple == a[b][2] ? 'past participle' : 'retry'
pastpart = gets.chomp
puts pastpart == a[b][3] ? 'compliments' : 'oh, no'

Array of objects as a field in a class. How to access parameters of single object?

I started yesterday with Ruby and have a problem.
I have two classes: Patient and Patient_history.
Patient can have multiple histories (from different appointments).
Here is what i have now:
class Patient
attr_accessor :name,
:surname,
:histories
def initialize(*)
#histories = []
end
def create_patient
#name = create_name_or_surname( "name")
#surname = create_name_or_surname("surname")
end
def create_name_or_surname( name_or_surname)
#not relevant in this case
end
def add_history(history)
#histories.push(history)
end
def print_patient
puts "name: #{#name}"
puts "surname : #{#surname}"
## I wish to do sth like:
## puts "history date: #{#histories[1].date}"
## to print content of Patient_history
end
end
And
class Patient_history
attr_accessor :date,
:description
def create_history
#date = create_date_or_desc("What is the date today?")
#description = create_date_or_desc("Write about an illness:")
end
end
with a line:
p patient
after setting history and patient values i get:
What is your name?
john
What is your surname?
smith
What is the date today?
12/12/2016
Write about an illness:
sick
#<Patient:0x007ffcb50ab518 #histories=[#
<Patient_history:0x007ffcb50aad98 #date="12/12/2016",
#description="sick">], #name="john", #surname="smith">
Can you give me a hint of what to do?
Question is a little vague, do you wish to print out the list of patient histories? You can iterate over each history using #each.
def print_patient
puts "name: #{#name}"
puts "surname : #{#surname}"
histories.each do |history|
puts "History Date: #{history.date}"
puts history.description
end
end

ruby class method unable to push additional user input to array

It stores the first employee, but when I try to add another employee I am unable to view the additional employees entered. Below is the method for viewing employee record. Thanks for any help!
Employee Class
class Employee
attr_accessor :employee, :role, :location
def initialize(employee, role, location)
#employee = employee
#role = role
#location = location
end
def employee_change(new_emp)
#employee = new_emp
end
def role_change(new_role)
#role = new_role
end.
def location_change(new_loc)
#location = new_loc
end
end
Main Menu
def main_menu
puts "Welcome to the Employee Portal"
puts "Please select an option below: "
puts "---------------------"
puts "1. Create New Employee Record."
puts "2. View an existing record."
puts "3. Modify an existing record."
puts "4. Exit Portal"
option = gets.chomp.to_i
if option == 1
create_record
main_menu
elsif option == 2
view_record
elsif option == 3
modify
elsif option == 4
puts "Thank you for using the Employee Portal"
exit
else
puts "Not a valid option. Please try again."
main_menu
system("clear")
end
end
Create New Employee (Option 1 from Main Menu)
def create_record
puts "Create New Employee Record, click 'Enter' to begin"
puts "Enter Employee Information: "
employee = gets.chomp.capitalize
puts "Enter Employee's Role: "
role = gets.chomp.capitalize
puts "Enter Employee's Current Work Location: "
location = gets.chomp.capitalize
puts "\n"
new_record = Employee.new(employee, role, location)
#record.push(new_record)
puts "New Employee Record has been created."
puts "Name: #{employee}"
puts "Role: #{role}"
puts "Location: #{location}"
system("clear")
main_menu
end
View Employee (Option 2 from Main Menu)
def view_record
puts "Enter Employee Name to view record: "
name = gets.chomp.capitalize
system("clear")
#record.each do |a|
if a.employee == name
puts "\n"
puts "Employee Information "
puts "--------------------"
puts " Name : #{a.employee}"
puts " Role(s) : #{a.role}"
puts " Location(s) : #{a.location}"
puts " Type 'Exit' to return to the Main Menu "
else
puts "That is not a valid entry, please try again."
view_record
main_menu
end
end
end
Modify Employee (Option 3 from Main Menu)
def modify
system("clear")
puts "Enter employee name to modify existing record: "
name = gets.chomp.capitalize
#record.each do |r|
if r.employee == name
puts "Employee found."
puts "Select an option to modify."
puts "-----------------------------------"
puts "1.) Modify employee's name."
puts "2.) Modify employee's role."
puts "3.) Modify employee's location."
puts "4.) Return to Main Menu"
puts "\n"
option = gets.chomp.to_i
if option == 1
change_employee
elsif option == 2
change_role
elsif option == 3
change_location
elsif option == 4
main_menu
else
puts "Invalid selection. Please try again."
modify
end
end
end
end
Change Employee (Option 1 from Modify)
def change_employee
puts "Enter new employee name: "
new_emp = gets.chomp.capitalize
#record.each do |r|
if r.employee == employee
r.employee_change(new_emp)
puts "#{r.employee} has been updated to #{r.employee}"
end
end
end
Change Employee Role (Option 2 from Modify)
def change_role
puts "What is #{r.employee}\'s new role?: "
new_role = gets.chomp.capitalize
#record.each do |r|
if r.employee == employee
r.role_change(new_role)
puts "#{r.employee}\'s new role is #{r.role}"
end
end
end
Change Employee Location (Option 3 from Modify)
def change_location
puts "What is #{r.employee}\'s new location?: "
new_loc = gets.chomp.capitalize
#record.each do |r|
if r.employee == employee
r.location_change(new_loc)
puts "#{r.employee} has been transfer to new location, #{r.location}."
end
end
end
Run the Program
#record = []
system("clear")
main_menu
The problem is with your view_record method. If you change it to look something like:
def view_record
puts "Enter Employee Name to view record: "
name = gets.chomp.capitalize
system("clear")
if a = #record.detect { |rec| rec.employee == name }
puts "\n"
puts "Employee Information "
puts "--------------------"
puts " Name : #{a.employee}"
puts " Role(s) : #{a.role}"
puts " Location(s) : #{a.location}"
puts " Type 'Exit' to return to the Main Menu "
else
puts "That is not a valid entry, please try again."
view_record
end
end
It works properly.
The problem was that you were calling the if...else statement on every record in #record. So if you create 2 Employees the first one named "John" and the second named "Jane". When you go to view "Jane", you call the else portion for "John", since he's the first record and then once he finishes the else you call the if portion for "Jane". The else for "John", however, never returns because after you finally finish a [possibly lengthy] stack of view_record calls, with the same issue, you then go back to main_menu which never returns (due to the final else condition in that method that re-calls main_menu)
Hope that helps and makes sense.
Notes:
The modify seems to have the same issue and the change_x methods will loop through and check each employee against the if statement, but since no else no problem (I'd still change them personally, to use the detect on these as well).
The change_x methods don't look like they would run, because employee isn't defined in them
If more than 1 employee can have the same name, you can use select instead of detect and then check for empty? or iterate through only those returned by select and call only the if portion on them.

Adding an Array to an Array Ruby

Im trying to learn how to add arrays into arrays, I have the following code:
puts "would you like to save a data set"
response = gets.chomp
if response == "y"
puts "create a new dataset?"
create_data_set = gets.chomp
while create_data_set == "y"
puts "what do you want to name the data set?"
dataset = gets.chomp
dataset = Array.new
puts 'would you like to add some grades to the array?'
store_grades_response = gets.chomp
while store_grades_response == "y"
puts 'enter grade ->'
grade = gets.chomp.to_i
dataset << grade
puts 'would you like to store another grade?'
store_grades_response = gets.chomp
end
all_data_sets = Array.new
all_data_sets.push(dataset)
puts "would you like to create a new data set?"
create_data_set = gets.chomp
end
end
puts all_data_sets
Im basically asking a user to enter a array name which should create an array, add values to the array and if required by the user add some more arrays and values to it. At last the array should be added to an array. And then I'm trying to display all the arrays.
The code works fine, I'm looping through everything but when it puts all_data_sets It only shows the last array that was created? i would like to store all the arrays within the one array called all_data_sets
The problem is that you are creating a new array all_data_sets at the end of each loop. One solution will be to have it before the loop.
puts "would you like to save a data set"
response = gets.chomp
all_data_sets = []
if response == "y"
puts "create a new dataset?"
create_data_set = gets.chomp
while create_data_set == "y"
puts "what do you want to name the data set?"
dataset = gets.chomp
dataset = Array.new
puts 'would you like to add some grades to the array?'
store_grades_response = gets.chomp
while store_grades_response == "y"
puts 'enter grade ->'
grade = gets.chomp.to_i
dataset << grade
puts 'would you like to store another grade?'
store_grades_response = gets.chomp
end
all_data_sets << dataset
puts "would you like to create a new data set?"
create_data_set = gets.chomp
end
end
puts all_data_sets
This way, you keep pushing the datasets into the all_data_sets after each loop.
I hope this is explanatory enough.
Fix
Its because your create new_data_sets array each time you do the loop, declare it outside enclosing while loop
Code
def main
mainDataSet = [] # All datasets
dataSetNames = [] # Incase you want to store data set names
response = getInput("Would you like to save a data set")
if(response == "y")
choice = getInput("Create a new dataset?")
while choice == "y"
dataset = getInput("What do you want to name the data set?")
dataSetNames << dataset
dataset = []
choice_2 = getInput("would you like to add some grades to the array?")
while choice_2== "y"
grade = getInput("Enter grade")
dataset << grade
choice_2 = getInput("Store another grade?")
end
mainDataSet << dataset
choice = getInput("Create a new data set?")
end
end
puts mainDataSet
puts dataSetNames
end
def getInput(message)
puts "#{message} -> "
gets.chomp
end
Hope this helps.
you can concat, prepend or append arrays just like this
dataset.concat all_dataset
dataset + all_dataset
Concat documentation
prepend or append
dataset.push(*all_dataset)
all_dataset.unshift(*dataset)
Array stuffs
Also you can do slice and whole bunch of stuffs check at the ruby docs link

Class-Array Interaction Ruby

I'm trying to set up a program to help me take care of grading for students in a class. I've set it up to make a class of student then to read in from the file (something I'm not very familiar with in Ruby) via an array. My programming experience is in java so if there are errors that can be explained by that I apologize. Thank you in advance for your help.
class Student
def initialize(str_LastName, str_FirstName, arr_Score)
#str_LastName = str_LastName
#str_FirstName = str_FirstName
#arr_Score = arr_Score
str_Grade = ""
int_OutOf = 415
end
def get_LastName
str_LastName
end
def get_FirstName
str_FirstName
end
def get_Grade
str_Grade
end
def set_TotalScore()
sum = 0
arr_Score.each do |item|
sum += item
end
arr_Score[12] = sum
end
def set_Grade
if arr_Score[12]/int_OutOf >= 0.9
str_Grade = "A"
elsif arr_Score[12]/int_OutOf >= 0.8
str_Grade = "B"
elsif arr_Score[12]/int_OutOf >= 0.7
str_Grade = "C"
elsif arr_Score[12]/int_OutOf >= 0.6
str_Grade = "D"
else
str_Grade = "F"
end
end
end
def main
file_name = "Grades"
arr_students = Array.new(31)
arr_scores = Array.new(12)
int_i = 0
file_io = open(file_name).readlines.each do |line|
array = line.split(",").map(&:strip)
student = Student.new(array[0],array[1],array[2..-2]) #the final element in the array is for the final score
arr_students[int_i] = student
puts "read #{arr_students[int_i]}"
end
file_name = "Graded"
file_io = open(file_name,"a+")
arr_students.each do |student|
set_TotalScore
set_Grade
file.io_write(student)
puts "write #{student}"
end
end
main if __FILE__==$0
Here is my run at it. I tried to stay true in general to the original intent of your code while introducing more Rubyish ways of doing things.
class Student
def initialize(firstname, lastname, *scores)
#firstname, #lastname, #scores = firstname, lastname, scores
end
def total_score
#scores.map(&:to_i).inject(:+)
end
def grade
raise "TOO HIGH!" if total_score > MAX_SCORE
case total_score / MAX_SCORE
when 0.9..1.0; "A"
when 0.8...0.9; "B"
when 0.7...0.8; "C"
when 0.6...0.7; "D"
else "F"
end
end
def to_s
"#{#lastname}, #{#firstname}: #{total_score}, #{grade}"
end
end
MAX_SCORE = 415.0
DATA.each_line do |line|
arr = line.split(",").map(&:strip)
student = Student.new *arr
puts student
end
__END__
Herb,Goldberg,22,99,44,22,88,88
Mark,Sullivan,77,88,88,44,33
You can read and write to files like this(not tested):
outfile = File.open("Graded", "a+")
File.open("Grades").each_line do |line|
...
outfile.puts student
end
outfile.close
We can not easily reproduce your code because you open a file called "Grades" and we do not have or know of its content.
You should also add some code to first check whether your file exists, before continuing - right now your script exits with a Errno::ENOENT.
I would also suggest putting the logic in main into your class instead - let your class handle everything.
In the part:
if __FILE__ == $PROGRAM_NAME
end
You can then simply initialize your class with a simple call such as:
Foobar.new(ARGV)
You described the "Grades" file but I did not understand what you wrote - it would be easier if you could link in to a sample, like via a pastie or gist, then link it in; and to also say what the part is that is not working, which is also unclear.
The style issues are secondary, I consider your code ok - the other poster here does not.
You should go through codecademy to get your ruby syntax down.
To access your initialized instance variables (#str_LastName (which should be #last_name), etc) you need to use "attr_reader :str_LastName", preferably at the top of the class. That'll definite you getter (setter is attr_writer, both is attr_accessor).
You can also do a sum on an array like this: [1,4,6,7].inject(:+).
Does Java not allow case statements? You should use that in set_grade. You also don't need to initialize str_Grade. In set grade, you could do #grade_letter ||= "A", and then calling set_grade will return that value on each call.
I didn't look through your main method. It's ugly though. Ruby methods probably shouldn't be more than 5 lines long.

Resources