Puts an array vertically and left justified - ruby

This is a follow up to one of my previous questions. When I run this program, the arrays are shown as ["1", "2", "3] etc.
This is my code:
#Table of Contents using an array
linewidth = 50
title = "Table of Consents"
#Needs chapters inputted
chapters = Array.new
puts "Please input chapter names."
while (input = gets.chomp) != ""
break if input.chomp.empty?
chapters << input
end
#Needs corresponding page numbers inputted
pagenumbers = Array.new
puts "Please input corresponding page numbers."
while (pagenum = gets.chomp) != ""
break if pagenum.chomp.empty?
pagenumbers << pagenum
end
leftside = chapters.to_s
rightside = "Pg. " + pagenumbers.to_s
puts title.center(50)
puts leftside.ljust(30) + rightside.rjust(30)
When I run it, it looks like this.
MBP-ERDOS:Programs chriserdos$ ruby TOCarray.rb
Please input chapter names.
born
dead
live
Please input corresponding page numbers.
1
43
99
Table of Consents
["born ", "dead", "live"] Pg. ["1", "43", "99"]
I'd like for the array to be printed like this:
born
dead
live
with the corresponding page numbers right justified on the same line.
New to Ruby, thank you for your help!

Get rid of all the code after your while loop and put this instead:
data = chapter.zip(pagenumbers)
puts title.center(50)
data.each do |left, right|
puts left.ljust(30) + right.rjust(30)
end

Just the strict answer to your question is:
puts title.center(50)
leftside.each_with_index { |x, i| puts "#{x.ljust(30)}#{rightside[i].rjust(30)}" }
But there is more methods to do it. Please take time to do some Ruby course or read a book, it is worth to do it.

Related

Looking for help cleaning up code

This is for an assignment for a class. I want to create a register type application for a donut shop. The application should accept "l" to list flavors, "a" to add flavors, "d" to delete flavors, and "e" to exit. The prices should be listed in ascending order. When adding a flavor, it should ask first the flavor, then the price.
I have the application working. It uses Jekyll (what the class uses).
item = {}
item_asc = {}
puts "Welcome to d0nutz flavor menu"
input = ""
division_line = lambda {30.times {|x| print "="}}
while input != "e"
division_line.call
puts "\n(l)ist flavors\n(a)dd a flavor\n(d)elete a flavor\n(e)xit application"
division_line.call
print "\nYour choice: "
input = gets.chomp
case input
when "l"
item_asc.each {|x,y| puts "Flavor: #{x} - Cost: $#{y}"}
when "a"
puts "Enter new flavor: "
flavor = gets.chomp
puts "Enter cost: "
cost = gets.chomp.to_i
item[flavor] = cost
item_asc = item.sort_by {|flavor,price| price}
input = ""
when "d"
puts "Enter a flavor to remove"
to_delete = gets.chomp
item.delete("#{to_delete}") {|x| puts "#{x} not found."}
item_asc = item.sort_by {|flavor,price| price}
item_asc.each {|x,y| puts "Flavor: #{x} - Cost: $#{y}"}
input = ""
when "e"
else
puts "\nThat is not a recognised command"
end
end
However it's even uglier than what I have here. I appreciate any input. I am interested in seeing what I should have done for clean up purposes, and maybe adding classes/methods where they should be, and making this more Rubyesque.
I would change the code to the following. This is not refactor since it is not equivalent to your code. In particular, it is not inconsistent like your code is. For example, when it prompts, it does not sometimes change a line and sometimes not as in your code; My code never changes a line. My code also always prints the list after an operation, unlike your code, which does not do so particularly when an item is added. Also, unlike your code, it does not end a message sometimes with and sometimes without a period; Messages in my code never end with period.
def prompt s
print "#{s}: "
gets.chomp
end
def list_items
#items.each{|k, v| puts "Flavor: #{k} - Cost: $#{v}"}
end
def sort_items
#items = #items.sort_by{|flavor, price| price}.to_h
list_items
end
puts "Welcome to d0nutz flavor menu"
#items = {}
loop do
puts(
?= * 30,
"(l)ist flavors",
"(a)dd a flavor",
"(d)elete a flavor",
"(e)xit application",
?= * 30,
)
case prompt("Your choice")
when ?l
list_items
when ?a
#items[prompt("Enter new flavor")] = prompt("Enter cost").to_i
sort_items
when ?d
#items.delete(prompt("Enter a flavor to remove")){|k| puts "#{k} not found"}
sort_items
when ?e
break
else
puts "That is not a recognised command"
end
end

Trouble summing an array in vanilla Ruby

I'm having trouble summing an array. Here's my existing code:
pageArray = Array.new
puts "How many pages long is the book you're reading?"
pageArray << gets.chomp
puts "Are you reading any other books right now?"
yn = gets.chomp
while yn != "no" do
puts "How many pages long is your next book?"
pageArray << gets.chomp
puts "Are you reading any other books right now?"
yn = gets.chomp
end
pageSum = pageArray.reduce(:+)
puts pageSum
When I go through and enter the values 100 and 50, the final return is "10050," rather than "150." Am I missing something obvious?
The code could be written more clearly, and more Ruby-like. Here's some untested code that is more idiomatic:
page_array = []
puts "How many pages long is the book you're reading?"
page_array << gets.chomp
loop do
puts 'Are you reading any other books right now?'
yn = gets.chomp.downcase
break if yn == 'no'
puts 'How many pages long is your next book?'
page_array << gets.chomp.to_i
end
page_sum = page_array.reduce(:+)
puts page_sum
Notice:
variables in Ruby are in snake_case, notInCamelCase.
loop do will loop forever. Simply break when you've received the break value.
you should fold the case of the value used as a break to catch variations in 'y' and 'Y'.
take the time to format your code so it's easily read, even for quick tests. It's amazing how often code we think is just a test actually gets put into production, so do it right the first time.
You are entering strings and concatenating them.
Use gets.chomp.to_i
You need to change the string you get from gets to an int.
pageArray << gets.chomp.to_i

Naming a new file with timestamp?

I'm trying to write a simple command line program that lets me keep track of how many times I get distracted during a study session.
I'm getting an argument error when I run this code saying my file.open has invalid arguments. If I want to name each new_session file with a timestamp, what would be a simple solution?
def first_question
puts "Would you like to start a new session?"
answer = gets.chomp
answer = answer.downcase
if answer == "yes"
new_session
else
puts "Ok. Would you like to review a previous session?"
prev_session = gets.chomp
prev_session.downcase
if prev_session == "yes"
#GET AND REVIEW PREVIOUS SESSIONS
elsif prev_session == "no"
puts "Well if you don't want a new session, and you don't want to review your old sessions, then you're SOL."
else
"That's not an acceptable response."
first_question
end
end
end
def new_session
distractions = 0
d = File.open("Session"+Time.now.to_s , 'w'){|f| f.write(distractions) }
puts "What would you like to do (add track(s) or review tracks)?"
request = gets.chomp
request.downcase
if request == "add track"
distractions = distractions.to_i + 1
puts "You have #{distractions} tracks in this session."
elsif request == "add tracks"
puts "How many times have you been distracted since we last met?"
answer = gets.chomp
distractions = distractions.to_i + answer.to_i
puts "You have #{distractions} tracks."
elsif request == "review tracks"
puts distractions
end
File.open( d , 'w') {|f| f.write(distractions) }
end
first_question
Most of your code is messy and redundant. The problem you are referring to, though, comes from here:
d = File.open("Session"+Time.now.to_s , 'w'){|f| f.write(distractions) }
d will be the number of bytes written to the file and thus a Fixnum. You can't open a Fixnum which you're trying to do in the last line of the function.
Further,
request = gets.chomp
request.downcase
The second line here does nothing.
You have two File.open statements:
d = File.open("Session"+Time.now.to_s , 'w'){|f| f.write(distractions) }
and:
File.open( d , 'w') {|f| f.write(distractions) }
Your error code will tell you which one is wrong, but, from looking at them, I'd say it's the second one.
d will be assigned the result of the block for the first File.open, which is going to be the result of f.write(distractions):
The File.open docs say:
The value of the block will be returned from File.open.
The File.write docs say:
Returns the number of bytes written.
As a result, you are assigning d a number of bytes, then trying to create a file with an integer for a filename, which is an error because a filename MUST be a string.
That leads to a bigger problem, which is, your code makes no sense.
d = File.open("Session"+Time.now.to_s , 'w'){|f| f.write(distractions) } writes a 0 to the file created by "Session"+Time.now.to_s.
request.downcase converts the contents of request to lowercase and immediately throws it away. Perhaps you meant request.downcase!, but it'd be better to write:
request = gets.chomp
request.downcase
As:
request = gets.chomp.downcase
distractions = distractions.to_i + 1? distractions is already 0 which is a Fixnum. You're converting a Fixnum to an integer using to_i then adding 1 to it. Simply do:
distractions += 1
distractions = distractions.to_i + answer.to_i should be:
distractions += answer.to_i
File.open( d , 'w') {|f| f.write(distractions) }, because it's trying to write to a file with the integer name, won't update your original file. If it succeeded, it'd write to an entirely new file, which would end up overwriting the previously created file, which was the result of writing a single 0 to disk. Instead, d should be the name of the file previously created.
Consider this:
def new_session
distractions = 0
puts "What would you like to do (add track(s) or review tracks)?"
request = gets.chomp.downcase
case request
when "add track"
distractions += 1
puts "You have #{distractions} tracks in this session."
when "add tracks"
puts "How many times have you been distracted since we last met?"
distractions += gets.chomp.to_i
puts "You have #{distractions} tracks."
when "review tracks"
puts distractions
end
File.write( "Session" + Time.now.to_s, distractions)
end
This code is cleaner, and makes more sense now.

Program to take input from command line into an array and find the biggest among them

I am new to Ruby and just can't figure out how you take input for an array from a user and display it.If anyone could clear that I can add my logic to find the biggest number.
#!/usr/bin/ruby
puts "Enter the size of the array"
n = gets.chomp.to_i
puts "enter the array elements"
variable1=Array.new(n)
for i in (0..n)
variable1[i]=gets.chomp.to_i
end
for i in (0..n)
puts variable1
end
How about capturing the array in one line?
#!/usr/bin/ruby
puts "Enter a list of numbers"
list = gets # Input something like "1 2 3 4" or "3, 5, 6, 1"
max = list.split.map(&:to_i).max
puts "The largest number is: #{max}"
You are doing it ok. But try this little change
#!/usr/bin/ruby
puts "Enter the size of the array"
n = (gets.chomp.to_i - 1)
puts "enter the array elements"
variable1=Array.new(n)
for i in (0..n)
variable1[i]=gets.chomp.to_i
end
puts variable1
or for undefined number of values here is one way
#!/usr/bin/ruby
puts "enter the array elements (type 'done' to get out)"
input = gets.chomp
arr = []
while input != 'done'
arr << input.to_i
input = gets.chomp
end
puts arr
I believe that this is a little bit more elegant solution.
puts "Please enter numbers separated by spaces:"
s = gets
a = s.split(" ")
#Displays array
puts a
#Displays max element
puts a.max
First you collect the series of numbers from the user, then you use a split method on the string, which converts it to the array. If you want to use some other separator, like "," than you can write s.split(","). After that you can use your logic to find the biggest number or you could just use max method.
Some feedback:
chomp.to_i is a bit redundant, since the latter will also remove newlines.
for x in y is not commonly seen in idiomatic Ruby code. It basically behaves like each with slightly different scoping rules and probably should have been removed from the language a while ago.
Ruby arrays are dynamic, so no need to preinitialize them. Something like (1..n).map { gets.to_i } would also produce the array you need.
Displaying it can then be done like this: array.each { |n| puts n }
Alternatively you can use the strip approach outlined before, take the numbers as command line arguments in ARGV or pipe into your program using ARGF.

How Do You Put 'gets' Input Into An Array?

Ruby noob here learning the ropes. I'm currently going through this tutorial and am working on this exercise:
Let's write a program which asks us to
type in as many words as we want (one
word per line, continuing until we
just press Enter on an empty line),
and which then repeats the words back
to us in alphabetical order.
I'm ignoring the alphabetical order part, for now.
Here is my code:
puts 'Hi, do you need something sorted?'
yn = gets.chomp
while yn != 'no'
puts 'What else?'
array = [gets]
yn = gets.chomp
end
puts 'Here\'s what you told me: ' +array.to_s
I've tweaked this for a few hours. To prevent my laptop from breaking due to an act of frustration I'm taking a break. Can anybody with more experience, and possibly more patience, point out my errors?
Keep in mind that every time you gets is a method that asks the user for input. On your lines:
array = [gets]
yn = gets.chomp
You are actually asking for input twice. Instead, store the user input somewhere (such as the array, see below) and get the stored value rather than asking the user twice.
Further, array = [gets] replaces the existing array with an array containing one element (the user input). You are never building up user input into the array. Instead, initialize the array before the while loop and use << in the loop:
array = Array.new
...
while yn != "no"
...
array << gets.chomp
yn = array.last
...
end
If you're having difficulty with something, the first thing you should do is try something simpler.
Rather than doing gets and looping, just try doing a simple gets.
puts 'Hi, do you need something sorted?'
yn = gets.chomp
Then I'd see if yn was what I expected.
The next thing I'd do is, rather than doing a loop many times, just try it once
puts 'Hi, do you need something sorted?'
yn = gets.chomp
if yn != 'no'
puts 'What else?'
array = [gets]
yn = gets.chomp
STDERR.puts "array is #{array.inspect}"
STDERR.puts "yn is #{yn.inspect}"
end
Then you'd hopefully realize that array and yn are both getting input, which wouldn't make sense.
For more hints on how to debug Ruby code, see How do I debug Ruby scripts?
I was having the same problem. Here is where I ended up (I think it meets all the specifications from the question):
puts 'Type in as many words as you\'d like. When you\'re finished, press enter on an empty line'
array = []
input = ' '
while input != ''
input = gets.chomp
array.push input
end
puts
puts array.sort
while yn != "no"
array << yn
print "What else? "
yn = gets.chomp
end
The "<<" appends yn to your array. (The only reason I used print is because it puts the cursor right next to the question mark instead of on the next line. No other reason)
#encoding:utf-8
x = Array.new
puts "enter something:".capitalize
y = ''
while y !=#nill
y = gets.chomp
x.push y
end
x.delete ('')
x.compact
puts "You entered: " + x.sort.to_s
puts "Objects in array: " + x.size.to_s
#made by ~Pick#chu!!!
Another way to read ‘Arrays’ from the console could be:
1: print “enter the values: ”
2: a = gets.chomp # input: “tom mark rosiel suresh albert”
3: array = a.split(‘ ‘) # .split() method return an array
4: p array # ["tom, "mark, "rosiel", "suresh", "albert"]
now, lets say you want an array of integers, all you have to do is:
# input “1 2 3 4 5″
3: array = a.split(‘ ‘).map{ |value| value.to_i }
4: p array # [1, 2, 3, 4, 5]
the clue here is to use a standard separator in order to use the .split() function.
here is how I've done this program:
array = [ ]
input = gets.chomp
while
input != ''
array.push input
input = gets.chomp
end
puts array
puts
puts array.sort

Resources