Reputation: 3
I need to implement a method, which works that way:
# do_magic("abcd") # "Aaaa-Bbb-Cc-D"
# do_magic("a") # "A"
# do_magic("ab") # "Aa-B"
# do_magic("teSt") # "Tttt-Eee-Ss-T"
My decision was to convert a string into an array, iterate through this array and save the result. The code works properly inside the block, but I'm unable to get the array with updated values with this solution, it returns the same string divided by a dash (for example "t-e-S-t" when ".map" used or "3-2-1-0" when ".map!" used):
def do_magic(str)
letters = str.split ''
counter = letters.length
while counter > 0
letters.map! do |letter|
(letter * counter).capitalize
counter -= 1
end
end
puts letters.join('-')
end
Where is the mistake?
Upvotes: 0
Views: 59
Reputation: 110725
I suggest the following.
def do_magic(letters)
length = letters.size
letters.downcase.each_char.with_index.with_object([]) { |(letter, i), new_letters|
new_letters << (letter * (length - i)).capitalize }.join
end
do_magic 'teSt'
# => "TtttEeeSsT"
Let's go through the steps.
letters = 'teSt'
length = letters.size
#=> 4
str = letters.downcase
#=> "test"
enum0 = str.each_char
#=> #<Enumerator: "test":each_char>
enum1 = enum0.with_index
#=> #<Enumerator: #<Enumerator: "test":each_char>:with_index>
enum2 = enum1.with_object([])
#=> #<Enumerator: #<Enumerator: #<Enumerator: "test":each_char>:
# with_index>:with_object([])>
Carefully examine the return values from the creation of the enumerators enum0
, enum1
and enum2
. The latter two may be thought of as compound enumerators.
The first element is generated by enum2
(the value of enum2.next
) and the block variables are assigned values using disambiguation (aka decomposition).
(letter, i), new_letters = enum2.next
#=> [["t", 0], []]
letter
#=> "t"
i #=> 0
new_letters
#=> []
The block calculation is then performed.
m = letter * (length - i)
#=> "tttt"
n = m.capitalize
#=> "Tttt"
new_letters << n
#=> ["Tttt"]
The next element is generated by enum2
, passed to the block and the block calculations are performed.
(letter, i), new_letters = enum2.next
#=> [["e", 1], ["Tttt"]]
letter
#=> "e"
i #=> 1
new_letters
#=> ["Tttt"]
Notice how new_letters
has been updated. The block calculation is as follows.
m = letter * (length - i)
#=> "eee"
n = m.capitalize
#=> "Eee"
new_letters << n
#=> ["Tttt", "Eee"]
After the last two elements of enum2
are generated we have
new_letters
#=> ["Tttt", "Eee", "Se", "T"]
The last step is to combine the elements of new_letters
to form a single string.
new_letters.join
#=> "TtttEeeSeT"
Upvotes: 0
Reputation: 6280
You can try something like this using each_with_index
def do_magic(str)
letters = str.split("")
length = letters.length
new_letters = []
letters.each_with_index do |letter, i|
new_letters << (letter * (length - i)).capitalize
end
new_letters.join("-")
end
OR
using map_with_index
equivalent each_with_index.map
def do_magic(str)
letters = str.split("")
length = letters.length
letters.each_with_index.map { |letter, i|
(letter * (length - i)).capitalize
}.join("-")
end
Upvotes: 1
Reputation: 5363
You're so close. When you have a block (letters.map!
), the return of that block is the last evaluated statement. In this case, counter -= 1
is being mapped into letters
.
Try
l = (letter * counter).capitalize
counter -= 1
l
Upvotes: 2