Basic Pig Latin | Troubles with .each - ruby

I'm solving a basic training exercise and I got stuck. I have to Move the first letter of each word to the end of it, then add 'ay' to the end of the word.. I've been googling and came up with this code:
def pig_it translate_pig_latin
move_letters = text.split(' ')
.each do {|x| x[1..-1] << x.[0] << 'ay' }
move_letters.join(' ')
end
But for some reason it gives me this error
-e:4: syntax error, unexpected '|', expecting '}'
.each do {|x| x[1..-1] << x.[0] << 'ay' }
I know it's a problem with the .each method, but after reading the documentation and googling around I can't figure out what's wrong with it.

def translate_pig_latin(text)
move_letters = text.split(' ')
.each { |x| return x[1..-1] << x[0] << 'ay' }
move_letters.join(' ')
end
Some notes -
As another user stated, don't mix and match do/end and {}
Also, when using bracket notation to retrieve an item from an array, don't use a . like you have in x.[0]
Your .each block is doing the correct thing(when you adhere to the above note) but isn't returning the result (by which I am confused). If you add an explicit return then your code works as above
A more drawn out method if this helps you understand what's happening better
def translate_pig_latin(text)
# create array to contain piglatinified phrase
new_phrase = []
# each word of the original phrase do
text.split(' ').each do |x|
# grab the characters after the first character
new_word = x[1..-1]
# add the first character plus 'ay' to the end of the string
new_word << x[0] + 'ay'
# add the newly piglatinified string to the phrase
new_phrase << new_word
end
# turn the phrase into a space separated string
new_phrase.join(' ')
end

Use either do...end or {...}. Don't mix them with do { as you did. That line should look like this:
.each { |x| x[1..-1] << x[0] << 'ay' }
or
.each do |x| x[1..-1] << x[0] << 'ay' end
From a style perspective, most Rubyists prefer to use {...} for single-line blocks and reserve do...end for blocks that span multiple lines of code.

Related

How to I get the right output when there is more than vowel in each word? My code only works with one vowel in each word

Aba is a German children’s game where secret messages are exchanged. In Aba,
after every vowel we add “b” and add that same vowel.
Write a method aba_translate that takes in a sentence string and returns a new
sentence representing its Aba translation. Capitalized words of the original sentence
should be properly capitalized in the new sentence.
aba_translate(“Cats and dogs”) #=> “Cabats aband dobogs”
aba_translate(“Everyone can code”) #=> “Ebeveryobonebe caban cobodebe”
aba_translate(“Africa is Africa in German”) #=> “Abafribicaba ibis Abafribicaba ibin
Gebermaban”
My code:
def aba_translate(sentence)
translation = []
words = sentence.split(" ")
vowels = "aeiou"
vowel = ""
before = ""
after = ""
full = ""
words.each do |word|
word.each_char.with_index do |char, idx|
if vowels.include?(char)
vowel = char
before = word[0...idx]
after = word[idx+1..-1]
full = before + vowel + "b" + vowel + after
translation << full
end
end
end
return translation.join(" ")
end
puts aba_translate("Cats and dogs")
puts aba_translate("Everyone can code")
puts aba_translate("Africa is Africa in German")
Your code generates a whole new word every time it sees a vowel. Instead you need to build each word character by character and make changes when it sees a vowel.
def aba_translate(sentence)
translation = []
words = sentence.split(" ")
vowels = "aeiouAEIOU"
words.each do |word|
full = ""
word.each_char.with_index do |char, idx|
full += char
if vowels.include?(char)
full = full + "b" + char.downcase
end
end
translation << full
end
return translation.join(" ")
end
Every time you find a vowel, you take the entire string before the vowel and the entire string after the vowel and add it to the result.
So, for a word like "code", that means you first produce the output c + obo + de and then the output cod + ebe.
However, what you actually need to do is simply keep the part you have processed instead of duplicating it.
You can do this by either changing your logic to keep track of up to which index you have already processed the word, or alternatively by processing it character-by-character instead of chunk-by-chunk.
However for problems like this, Regex are usually a much better solution:
VOWELS = 'aeiou'
def aba_translate(sentence)
sentence.gsub(Regexp.union(*VOWELS.chars), '\0b\0')
end
or just making VOWELS a Regexp in the first place:
VOWELS = /[aeiou]/.freeze
def aba_translate(sentence)
sentence.gsub(VOWELS, '\0b\0')
end
I think the nested loops complicates it since you can solve the problem with just one loop. Here you just need to initialize a string and a string of vowels to check each character. While you iterate through each character you shovel it into the empty string, and then you check if it is a vowel you shovel b + that vowel's lowercase version to account for the uppercase instances. Then you finally return the new string.
def aba_translate(string)
new_string = ""
vowels = "AEIOUaeiou"
string.each_char do |char|
new_string << char
if vowels.include?(char)
new_string << "b" + char.downcase
end
end
return new_string
end
Here's my beginner-friendly solution
def aba_translate(sent)
vowels = "AEIOUaeiou"
aba_sent = ""
sent.each_char do |char|
if vowels.include?(char)
aba_sent += char + "b" + char.downcase
else
aba_sent += char
end
end
return aba_sent
end

How to use gsub with a file in Ruby?

Hey I've a little problem, I've a string array text_word and I want to replace some letters with my file transform.txt, my file looks like this:
/t/ 3
/$/ 1
/a/ !
But when I use gsub I get an Enumerator back, does anyone know how to fix this?
text_transform= Array.new
new_words= Array.new
File.open("transform.txt", "r") do |fi|
fi.each_line do |words|
text_transform << words.chomp
end
end
text_transform.each do |transform|
text_word.each do |words|
new_words << words.gsub(transform)
end
end
You can see String#gsub
If the second argument is a Hash, and the matched text is one of its
keys, the corresponding value is the replacement string.
Also you can use IO::readlines
File.readlines('transform.txt', chomp: true).map { |word| word.gsub(/[t$a]/, 't' => 3, '$' => 1, 'a' => '!') }
gsub returns an Enumerator when you provide just one argument (the pattern). If you want to replace just add the replacement string:
pry(main)> 'this is my string'.gsub(/i/, '1')
"th1s 1s my str1ng"
You need to refactor your code:
text_transform = Array.new
new_words = Array.new
File.open("transform.txt", "r") do |fi|
fi.each_line do |words|
text_transform << words.chomp.strip.split # "/t/ 3" -> ["/t/", "3"]
end
end
text_transform.each do |pattern, replacement| # pattern = "/t/", replacement = "3"
text_word.each do |words|
new_words << words.gsub(pattern, replacement)
end
end

Ruby Multiple Words Pig Latin

I'm having trouble with a Ruby pig latin translator translating 2 or more words. I've successfully figured out how to translate words beginning with a vowel, consonant, or two consonants with my function translate, and I'm wanting to create a second function, translate_words, that uses .map with the first function.
When the string, "eat pie", gets submitted, the output is "eat pieay". It only changes the second word and also does it incorrectly (should be "eatay iepay"). I've looked at multiple other solutions on SO without luck. I'm still very new with regex so those solutions were a little over my head.
This project works with RSpec and I've added the test code below mine.
Here's my code:
def translate(input)
pig_string = ''
if input[0] =~ /[aeiou]/
return input + 'ay'
elsif input[0] =~ /[^aeiou]/ && input[1] =~ /[aeiou]/
return input[1..-1] + input[0] + 'ay'
elsif input[0..1] =~ /[^aeiou]/
return input[2..-1] + input[0..1] + 'ay'
else
return input[0] + input + 'ay'
end
end
def translate_words(multi_words)
word_count = multi_words.split.size
if word_count > 1
multi_words.map! do |word|
translate(word)
end
end
end
RSpec:
it "translates two words" do
s = translate("eat pie")
expect(s).to eq("eatay iepay")
end
As per comments above by bitsapien and Sergio Tulentsev :
def translate_words(multi_words)
multi_words.split.map do |word|
translate(word)
end.join(' ')
end
map will suffice instead of map!.
translate_words('eat plie') #=> "eatay ieplay"

How can I check for first letter(s) in string in Ruby?

I'm writing test file, but I can't get it pass second test, here:
def translate(word)
if word.start_with?('a','e','i','o','u')
word << "ay"
else
word << "bay"
end
end
Is start_with? the right method to do the job?
describe "#translate" do
it "translates a word beginning with a vowel" do
s = translate("apple")
s.should == "appleay"
end
it "translates a word beginning with a consonant" do
s = translate("banana")
s.should == "ananabay"
end
it "translates a word beginning with two consonants" do
s = translate("cherry")
s.should == "errychay"
end
end
EDIT:
My solution is not complete.
My code pass first test only because I was able to push "ay" to the end of word. What I'm missing to pass the second test is to remove the first letter if its consonant, which is "b" in "banana".
You can do this also:
word << %w(a e i o u).include?(word[0]) ? 'ay' : 'bay'
Using a Regex might be overkill in your case, but could be handy if you want to match more complex strings.
word << word[0].match(/a|e|i|o|u/).nil? ? 'bay' : 'ay'
Your code means:
if word start with ('a','e','i','o','u') add "ay" at the end
else add "bay" at the end.
Second test will be "bananabay" and not "ananabay" (with b as first letter)
def translate(word)
prefix = word[0, %w(a e i o u).map{|vowel| "#{word}aeiou".index(vowel)}.min]
"#{word[prefix.length..-1]}#{prefix}ay"
end
puts translate("apple") #=> "appleay"
puts translate("banana") #=> "ananabay"
puts translate("cherry") #=> "errychay"
Looks like you are removing the first character if the word starts with a consonant too, so:
if word.start_with?('a','e','i','o','u')
word[0] = ''
word << 'ay'
else
consonant = word[0]
word << "#{consonant}ay"
end
The below piece of code passes all the tests...
def translate(word)
if word.start_with?('a','e','i','o','u')
word<<'ay'
else
pos=nil
['a','e','i','o','u'].each do |vowel|
pos = word.index(vowel)
break unless pos.nil?
end
unless pos.nil?
pre = word.partition(word[pos,1]).first
word.slice!(pre)
word<<pre+'ay'
else
#code to be executed when no vowels are there in the word
#eg words fry,dry
end
end
end
Figured I'd share my first contribution!
Good luck!
def method(word)
word[0].eql?("A" || "E" || "I" || "O" || "U")
end

Ruby: Method return without a block

I am trying to make this code return when called without a block. The uncommented lines at the bottom is what I'm trying to get to return. The first uncommented line should return in tut, second line converted to english and the last should be in english. And why is the line " puts eng " returning up and down and not in sentence form? Thanks for any and all help.
Here's my code:
class Tut
##consonants = ["b","c","d","f","g","h","j","k","l","m","n","p","q","r","s","t","v","w","x","y","z"]
def is_tut? string
if string =~ /^(([b-df-hj-np-z]ut)|([aeiou\s])|[[:punct:]])+$/i
yield
else
false
end
end
def self.to_tut string
string.each_char do |c|
c += "ut" if ##consonants.find { |i| i == c.downcase }
yield c if block_given?
end
end
def self.to_english string
array = string.split //
array.each do |c|
if ##consonants.find { |i| i == c.downcase }
array.shift
array.shift
end
yield c if block_given?
end
end
end
#Tut.to_tut( "Wow! Look at this get converted to Tut!" ) { |c| print c }
# should output : Wutowut! Lutookut atut tuthutisut gutetut cutonutvuteruttutedut tuto Tututut!
#puts
#puts
tut = Tut.to_tut( "Wow! Look at this get converted to Tut!" )
puts "from return: #{tut}"
puts
#Tut.to_tut( "Wutowut! Lutookut atut tuthutisut gutetut cutonutvuteruttutedut tuto Tututut!" ) { |c| print c }
#should outout : Wutowut! Lutookut atut tuthutisut gutetut cutonutvuteruttutedut tuto Tututut!
#puts
#puts
tut = Tut.to_tut( "Wutowut! Lutookut atut tuthutisut gutetut cutonutvuteruttutedut tuto Tututut!" )
puts "from return: #{tut}"
#puts
#tut_string = ""
#Tut.to_tut( "I'm in tut but I want to be in english." ) { |c| tut_string += c }
#puts tut_string
# should output : I'mut inut tututut bututut I wutanuttut tuto bute inut enutgutlutisuthut.
puts
#Tut.to_english( tut_string ){ |c| print c }
# should output : I'm in tut but I want to be in english.
lan = Tut.to_english( tut )
puts lan
(Opening note: You normally don't want to modify an Enumerable object while iterating over it, since that makes it much harder to read the code and debug it.)
Your to_tut doesn't retain your modifications because the "c" block variable is a copy of the string slice, instead of a reference to part of the string (if it were a ref, you'd be able to use << to append; "+=" still wouldn't work because it reassigns rather than changing the ref). That's just how each_char works, since a String doesn't contain references.
If you wanted to modify the string in place, you'd probably have to count backwards and then insert the 'ut' by index via string#[]= . But that's way complicated so I'll present a couple alternates.
Working to_tut #1:
def self.to_tut string
string.chars.map do |c|
yield c if block_given?
# this must be the last expression the block
if ##consonants.find { |i| i == c.downcase }
c + 'ut'
else
c
end
end.join
end
Working to_tut #2 - this is probably the most ruby-ish way to do it:
def self.to_tut string
string.gsub(/[#{##consonants.join}]/i) {|match|
yield match if block_given?
# this must be the last expression in the block
match + 'ut'
}
end
Your to_english doesn't work because array.shift always removes the first element of the array. Instead, you want to track the current index, and remove 2 chars starting from index+1.
Working to_english:
def self.to_english2 string
array = string.split //
array.each_with_index do |c, idx|
if ##consonants.find { |i| i == c.downcase }
array.slice!(idx+1, 2)
end
yield c if block_given?
end
array.join
end
Regarding why your "puts lan" returns one char per line - it's because your to_english returns an array. You'll want to call join to convert it.
The methods to_tut and to_english are giving you wrong answers when used without a block. This happens because ruby always returns the last value evaluated in your method. In your code that will be the result of the string.each_char for to_tut or array.each for to_english. In both cases, the result contains the original input, which is consequently returned and printed.
As to the puts eng, it prints the array returned by array.each of to_english.

Resources