How do I get the last elements of an array in Ruby? - arrays

How do I pull the values from an array like you do with .map? Here's my code:
counter = 0
ary = Array.new
puts "How many teams do you have to enter?"
hm = gets.to_i
until counter == hm do
puts "Team City"
city = gets.chomp
puts "Team Name"
team = gets.chomp
ary.push([city, team])
counter += 1
end
ary.map { |x, y|
puts "City: #{x} | Team: #{y}"
}
print "The last team entered was: "
ary.last
The end result looks like this:
City: Boston | Team: Bruins
City: Toronto | Team: Maple Leafs
The last team entered was:
=> ["Toronto", "Maple Leafs"]
But I want the last line to read
The last team entered was: Toronto Maple Leafs
How do I get my values in that line without the =>, brackets and quotes?

Basically, you question is “how to join string array elements into a single string,” and Array#join comes to the rescue:
["Toronto", "Maple Leafs"].join(' ')
#⇒ "Toronto Maple Leafs"

An alternative way with *:
puts ["Toronto", "Maple Leafs"] * ', '
#Toronto, Maple Leafs
#=> nil
But I don't think anyone uses this notation, so as recommended in another answer use join.

Use print instead of puts when you don't want a new line character at the end of the line for example when getting user input, furthermore you can also use #{variable} to print within the same line using puts:
counter = 0
ary = Array.new
print "How many teams do you have to enter? "
hm = gets.to_i
until counter == hm do
print "Team #{counter + 1} City: "
city = gets.chomp
print "Team #{counter + 1} Name: "
team = gets.chomp
ary.push([city, team])
counter += 1
end
ary.map { |x, y| puts "City: #{x} | Team: #{y}" }
puts "The last team entered was: #{ary.last.join(' ')}"
Example Usage:
How many teams do you have to enter? 2
Team 1 City: Boston
Team 1 Name: Bruins
Team 2 City: Toronto
Team 2 Name: Maple Leafs
City: Boston | Team: Bruins
City: Toronto | Team: Maple Leafs
The last team entered was: Toronto Maple Leafs
Try it here!

Try it:
team_last = ary.last
puts "The last team entered was:" + team_last[0] + team_last[1]

As per your code ary.last itself return an array so first you would need to convert it to a string by joining the two elements in the array by ary.last.join(' ') and then you will have to interpolate it with the your message string i.e "The last team entered was: #{ary.last.join(' ')}"
The last two lines of your code would change to :
print "The last team entered was: #{ary.last.join(' ')}"

Related

How to compare letters in two strings Ruby

I am new to ruby and creating a hangman game. Soo far I have my code comparing the words to the correct word. But I want it to compare letters. So basically, if the secrect word is glue, the user enters G it would come inncorrect, but if the user enters glue it would be correct. I need it to compare letter by letter just like hangman.
Having a bit of trouble with that. I have attached my code below.
secret_word = []
puts "enter a word to be guessed"
secret_word = gets.chomp
guess_letters = []
guess = ""
guess_limit = 3
guess_count = 0
out_of_guesses = false
while guess != secret_word and !out_of_guesses
if guess_count < guess_limit
puts "enter your guess: "
guess = gets.chomp()
guess_letters << guess
guess_count +=1
puts "you have used these letters thus far #{guess_letters.join(", ")}"
else
out_of_guesses = true
end
end
if out_of_guesses
puts "you Lose, the word was #{secret_word}"
else
puts "you win"
end
I'm not sure which hangman rules you are using but here's a rough draft that allows three failed attempts and works with lowercase characters
def guess_word(word, tries)
if tries < 1
puts "You are hanged!"
elsif word.empty?
puts "You guessed it! You are saved from the gallows!"
else
print "Enter character: "
c = STDIN.getc.downcase
STDIN.getc # get rid of newline
if word.index(c).nil?
puts "Ooops, #{c} was wrong!"
guess_word(word, tries - 1)
else
puts "#{c} was correct!"
guess_word(word.sub(/["#{c}"]/, ''), tries)
end
end
end
if __FILE__ == $0
TRIES = 3
print "Enter word to guess: "
word = gets.chomp
guess_word(word.downcase, 3)
end
This is untested..
The rules of the game hangman are given at its Wiki. I've assumed the player trying to guess the word loses when all seven parts of the man on the gallows have been drawn (head, neck, left arm, body, right arm, left leg, right leg).
Helper methods
Draw the man being hanged
First create a hash that can be used to draw the partial or full hangman:
MAN = [" O\n", " |\n", "\\", "|", "/\n", " |\n/", " \\"].
map.each_with_object([""]) { |s,arr| arr << (arr.last + s) }.
each.with_index.with_object({}) { |(s,i),h| h[i] = s }
The keys are the number of incorrect guesses. For example:
puts MAN[2]
O
|
puts MAN[6]
O
|
\|/
|
/
Keep track of the positions of the letters of the word
Next create a hash whose keys are unique letters of the secret word and whose values are arrays of indices of the keys location(s) in the word.
def construct_unknown(word)
word.each_char.with_index.with_object({}) { |(c,i),h| (h[c] ||= []) << i }
end
For example,
unknown = construct_unknown("beetle")
#=> {"b"=>[0], "e"=>[1, 2, 5], "t"=>[3], "l"=>[4]}
We will also create an empty hash for letters whose positions are known:
known = {}
Move guessed letters from the hash unknown to the hash known
If a letter that is guessed is a key of unknown that key and value are moved to known.
def move_unknown_to_known(letter, unknown, known)
known.update(letter=>unknown[letter])
unknown.delete(letter)
end
For example (for unknown and known above),
move_unknown_to_known("e", unknown, known)
unknown #=> {"b"=>[0], "t"=>[3], "l"=>[4]}
known #=> {"e"=>[1, 2, 5]}
See if the guesser has won or lost
We to determine when, after guessing a letter, the player has won or lost, or is to continue:
def win?(word_size, known)
known.values.flatten.sum == word_size
end
def lose?(wrong_guess_count)
wrong_guess_count == HANGMAN.size
end
For example,
win?(word.size, known)
#=> false
lose?(6) #=> false
lose?(7) #=> true
Display the known letters
def display_known(word_size, known)
known.each_with_object('_' * word_size) { |(k,a),s| a.each { |i| s[i] = k } }
end
For example (recall word #=> "beetle"),
puts display_known(word.size, known)
_ee__e
Main method
We are now ready to write the main method.
def hangman
puts "Player 2, please avert your eyes for a moment."
print "Player 1: enter a secret word with at least two letters: "
word = gets.chomp.downcase
unknown = construct_unknown(word)
known = {}
wrong_guess_count = 0
loop do
puts display_known(word.size, known)
puts MAN[wrong_guess_count] if wrong_guess_count > 0
if win?(word.size, known)
puts "You win! You win! Congratulations!"
break
end
if lose?(wrong_guess_count)
puts "Sorry, but you've run out of guesses"
break
end
print "Player 2: enter a letter or your guess of the word: "
guess = gets.chomp.downcase
if guess.size > 1
if guess == word
puts word
puts "You win! You win! Congratulations!"
break
else
puts "Sorry, that's not the word"
wrong_guess_count += 1
end
elsif unknown.key?(guess)
nbr = unknown[guess].size
puts nbr == 1 ? "There is 1 #{guess}" : "There are #{nbr} #{guess}'s"
move_unknown_to_known(guess, unknown, known)
else
puts "Sorry, the word contains no #{guess}'s"
wrong_guess_count += 1
end
end
end
Example
After explaining the rules to the two players and to the audience, the guest host ends by saying, "And don't forget, when guessing a letter or the word it must be expressed as a question...one moment...hold that...I've been told it is not necessary to frame that as a question".
Suppose the word is beetle and the letter guesses are 't', 'i', 'a', 'l', 'r', 's', 't', 'u', 'e', 'beetle'.
hangman
Player 2, please avert your eyes for a moment.
Player 1: enter a secret word with at least two letters: beetle
______
Player 2: enter a letter or your guess of the word: t
There is 1 t
___t__
Player 2: enter a letter or your guess of the word: i
Sorry, the word contains no i's
___t__
O
Player 2: enter a letter or your guess of the word: a
Sorry, the word contains no a's
___t__
O
|
Player 2: enter a letter or your guess of the word: l
There is 1 l
___tl_
O
|
Player 2: enter a letter or your guess of the word: r
Sorry, the word contains no r's
___tl_
O
|
\
Player 2: enter a letter or your guess of the word: s
Sorry, the word contains no s's
___tl_
O
|
\|
Player 2: enter a letter or your guess of the word: t
Sorry, the word contains no t's
___tl_
O
|
\|/
Player 2: enter a letter or your guess of the word: u
Sorry, the word contains no u's
___tl_
O
|
\|/
|
/
Player 2: enter a letter or your guess of the word: e
There are 3 e's
_eetle
O
|
\|/
|
/
Player 2: enter a letter or your guess of the word: beetle
beetle
You win! You win! Congratulations!

Add the last index of an array with a unique seperator

I am trying to get the last character of an array to join with it's own character. I'm having trouble trying to figure this out on my own I'm still unfamiliar with built in methods on ruby. Here's where I'm at so far:
def list(names)
#last = names.last
joined = names.map(&:values).flatten.join(", ")
#joined.pop
#joined << last.join(" &")
end
What I want to do is for the last index I want to join it with it's own character. I've tried doing this for hours but I keep getting errors. If anyone can point me in the right direction on this I would greatly appreciate it.
My target goal for an output would be
list([{name: 'Bart'},{name: 'Lisa'},{name: 'Garry'}])
to output:
"Bart, Lisa & Gary"
I suggest creating the string with all names separated by commas (e.g., "Bart, Lisa, Garry") and then replacing the last comma with " &". Here are two ways to do that.
Code
def list1(names)
all_commas(names).tap { |s| s[s.rindex(',')] = ' &' }
end
def list2(names)
all_commas(names).sub(/,(?=[^,]+\z)/, ' &')
end
def all_commas(names)
names.map(&:values).join(', ')
end
Example
names = [{ name: 'Bart' }, { name: 'Lisa' } , { name: 'Garry' }]
list1 names
#=> "Bart, Lisa & Garry"
list2 names
#=> "Bart, Lisa & Garry"
Explanation
The steps are as follows.
For all_commas:
a = names.map(&:values)
#=> [["Bart"], ["Lisa"], ["Garry"]]
a.join(', ')
#=> "Bart, Lisa, Garry"
For list1
s = all_commas(names)
#=> "Bart, Lisa, Garry"
i = s.rindex(',')
#=> 10
s[i] = ' &'
#=> " &"
s #=> "Bart, Lisa & Garry"
tap's block returns s
For list2
a = all_commas(names)
#=> "Bart, Lisa, Garry"
a.sub(/,(?=[^,]+\z)/, ' &')
# => "Bart, Lisa & Garry"
The regular expression, which employs a positive lookahead, reads, "match a comma, followed by one or more characters other than comma, followed by the end of the string".
Here's a solution that yields your desired output, given your input:
def list(names)
*head, tail = names.map(&:values)
[head.join(", "), tail].join(" & ")
end
Enjoy!
Here's a solution with the Oxford comma, which I prefer :)
def list(name_list)
*names, last = name_list.flat_map(&:values)
oxford_comma = names.size > 1 ? ", " : ""
names.join(", ") + oxford_comma + "& #{last}"
end
(Note: if this is Rails, Array#to_sentence does this automatically.)

Issues with the output format of hash

So I was trying to create a program that resembles a grocery list where the user puts the item and its associated cost and it would display it as a form of a list. So I created this:
arr = []
arr2 = []
entry = " "
while entry != "q"
print "Enter your item: "
item = gets.chomp
print "Enter the associated cost: "
cost = gets.chomp.to_f
print "Press any key to continue or 'q' to quit: "
entry = gets.chomp
arr << item
arr2 << cost
end
h = { arr => arr2 }
for k,v in h
puts "#{k} costs #{v}"
end
(Code is probably very inefficient, but with my limited starter knowledge it's the best I can do)
So my problem is when I try more than two items the results would display like this (Let's say I used Banana and Kiwi for item and put a random number for their costs):
["Banana", "Kiwi"] costs [2.0, 3,0]
I, however, would like it to display like this:
Banana costs $2.00
Kiwi costs $3.00
I know it probably has to do something with this line:
h = { arr => arr2 }
But I just don't know what I can change about it. I already spend hours trying to figure out how it works so if anyone can give me a hint or help me out I would appreciate it! (Also my apologies for the vague title, didn't know better on how to describe it...)
yes, you are correct. Problem is with this line h = { arr => arr2 }. This line will create a hash like h = {["Banana", "Kiwi"] => [2.0, 3,0]}.
1) You can modify your code as below if you want to use two arrays.
(0...arr.length).each do |ind|
puts "#{arr[ind]} costs $#{arr2[ind]}"
end
2) Better, you can use a hash to store the item and it's cost and then iterate over it to show the results
hash = {}
entry = " "
while entry != "q"
print "Enter your item: "
item = gets.chomp
print "Enter the associated cost: "
cost = gets.chomp.to_f
print "Press any key to continue or 'q' to quit: "
entry = gets.chomp
hash[item] = cost
end
hash.each do |k,v|
puts "#{k} costs $#{v}"
end
You are storing the item names and their costs in 2 different arrays. So, if want to keep your storage structure like that only, you will need to modify the display of result as below:
arr.each_with_index do |item, i|
puts "#{item} costs #{arr2[i]}"
end
But a better approach would be to store all the data in 1 hash instead of 2 arrays.
items = {}
entry = " "
while entry != "q"
print "Enter your item: "
item = gets.chomp
print "Enter the associated cost: "
cost = gets.chomp.to_f
print "Press any key to continue or 'q' to quit: "
entry = gets.chomp
items[item] = cost
end
items.each do |item, cost|
puts "#{item} costs #{cost}"
end
Let me know if it helps.

Ruby loop and array

I've been trying to teach myself Ruby. I've found a few code problems to try solving, but I'm stuck. Here is what I have and the problems I'm trying to solve.
My algorithm is as follows:
Prompt the user to enter a number between 1 and 10 (inclusive).
Read that number into an appropriately named variable.
Test that the number lies in the appropriate range.
Input new number if it is out of bounds as per the condition.
Use the number entered by the user to create an array with that
number of elements.
Write a loop which will run through a number of iterations equal to
the size of the array.
Each time through, prompt the user to enter a text string - a name
(names of cars, that sort of thing).
Once the array is entered, display the contents of the array three
items to a line.
You will want a for loop for this, and within the for loop you should include a decision which will insert a line break at the appropriate places.
Also,
Separate the array elements with dashes - but do not put a dash
before the first element on a line, and do not put a dash after the
last element on a line.
Use a Ruby function to sort the array alphabetically, then display it
again, the same way as before.
Reverse the order of the array
Display its contents a third time, again putting three elements on each line of output and placing dashes the way you did with the first display effort.
loop do
print "Enter an integer between 1 and 10: "
s = gets.chomp.to_i
if s >0 && s <= 10
break
else
puts "Interger entered is outside specified range."
end
end
array=[]
array.size
loop do
print "Enter name of a car model: "
car=gets.chomp
array<<car
for i in array
array.slice(1..9) {|car|
puts car.join(", ")
}
end
end
Is that solution you looking for?
loop do
print "Enter an integer between 1 and 10: "
s = gets.chomp.to_i
if (1..10).include?(s)
arr = [""] * s
i = 0
while i < arr.length
print "Enter name of a car model: "
car = gets.chomp
arr[i] = car
i += 1
end
puts arr.join(", ")
break
else
puts "Interger entered is outside specified range."
break
end
end
Result is:
[retgoat#iMac-Roman ~/temp]$ ruby loop.rb
Enter an integer between 1 and 10: 2
Enter name of a car model: car_a
Enter name of a car model: car_b
car_a, car_b
UPDATE
Below solution to print an array by 3 elements per line with natural sorting
loop do
print "Enter an integer between 1 and 10: "
s = gets.chomp.to_i
if (1..10).include?(s)
arr = [""] * s
i = 0
while i < arr.length
print "Enter name of a car model: "
car = gets.chomp
arr[i] = car
i += 1
end
puts arr.sort.each_slice(3){ |e| puts "#{e.join(", ")}\n"}
break
else
puts "Interger entered is outside specified range."
break
end
end
Result is:
[retgoat#iMac-Roman ~/temp]$ ruby loop.rb
Enter an integer between 1 and 10: 4
Enter name of a car model: z
Enter name of a car model: a
Enter name of a car model: x
Enter name of a car model: b
a, b, x
z
And reverse sorting:
loop do
print "Enter an integer between 1 and 10: "
s = gets.chomp.to_i
if (1..10).include?(s)
arr = [""] * s
i = 0
while i < arr.length
print "Enter name of a car model: "
car = gets.chomp
arr[i] = car
i += 1
end
puts arr.sort{ |x, y| y <=> x }.each_slice(3){ |e| puts "#{e.join(", ")}\n"}
break
else
puts "Interger entered is outside specified range."
break
end
end
Result is:
[retgoat#iMac-Roman ~/temp]$ ruby loop.rb
Enter an integer between 1 and 10: 4
Enter name of a car model: z
Enter name of a car model: a
Enter name of a car model: x
Enter name of a car model: b
z, x, b
a
It's better to split you program into small pieces. Also, try not to use loop without necessity.
# Specify Exception class for your context
class ValidationException < RuntimeError
end
def number_of_cars_from_input
# Get user input
print 'Enter an integer between 1 and 10: '
number = gets.chomp.to_i
# Validate input for your requirements
unless (1..10).cover?(number)
raise ValidationException, 'Interger entered is outside specified range.'
end
number
rescue ValidationException => err
# Print exception and retry current method
puts err
retry
end
# Get car name from user input
def car_from_input
print 'Enter name of a car model: '
gets.chomp
end
# Create array with size equal to number from imput and fill it with cars
array_of_cars = Array.new(number_of_cars_from_input) { car_from_input }
# Separate cars in groups by 3 and join groups
puts array_of_cars.each_slice(3).map { |a| a.join(', ') }

How to have the user input alternate between uppercase and lowercase in Ruby?

I have Ruby ask the user five times to enter a name, and want the answers to be spat out with each line to alternate with uppercase and lowercase. Below is what I have done and it prints out each name twice, one uppercase one lowercase. But I just want each line to alternate between uppercase and lowercase. I hope I'm making sense here...
Football_team = []
5.times do
puts "Please enter a UK football team:"
Football_team << gets.chomp
end
Football_team.each do |Football_team|
puts team.upcase
puts team.downcase
end
football_team = []
5.times do
puts "Please enter a UK football team:"
football_team << gets.chomp
end
football_team.each_with_index do |team, index|
if index.even?
puts team.upcase
else
puts team.downcase
end
end
Note that you should use identifiers starting with capitals only for constants. While Football_team might be a constant, it is generally not a good idea. Also note that your loop variable was wrong.
You don't really need two loops. You can do it all in one. See below
football_team = []
5.times do |i|
puts "Please enter a UK football team:"
team = gets.chomp
if i.even?
football_team << team.upcase
else
football_team << team.downcase
end
end
puts football_team
Alternatively, same solution but in shorthand:
football_team = []
5.times do |i|
puts "Please enter a UK football team:"
i.even? ? football_team << gets.chomp.upcase : football_team << gets.chomp.downcase
end
puts football_team

Resources