I am starting a challenge that will help me refresh the basics of solving small coding problems. I use Launch School’s PEDAC framework to walk through the problem-solving process.
Today is the first time I’ve actually coded something for a while, so I eased myself in to the challenge with a Codewars 7 kyu problem. It was fun and it refreshed some key concepts in my brain.
I began by reading the problem. Essentially, it was asking me to take an integer and return an array of integer strings that start with the first digit, then include the first digit and second digit, and so on until the last element in the array is the string form of the original integer.
# Examples
# 420 should return ["4", "42", "420"]
# 2017 should return ["2", "20", "201", "2017"]
# 2010 should return ["2", "20", "201", "2010"]
# 4020 should return ["4", "40", "402", "4020"]
# 80200 should return ["8", "80", "802", "8020", "80200"]
# PS: The input is guaranteed to be an integer in the range [0, 1000000]
I began my PEDAC process by breaking down the problem a bit.
=begin
Input: integer
Output: array of string integers
Rules: between 0 and a million. if just one number, will only convert that one number to string and add to the array.
Problem: take given number, convert to string, prepend to array, remove last digit, repeat until no more digits
DS: integer, strings, array
Algo:
initialize a result array, []
initialize lv string_num, assign to the return value of converting a given num to a string
until the string_num is equal to "", prepend string_num to result
remove last character from string_num
- convert to array, remove last character
- call pop on return value of chars called on string, convert back to string with .to_s, reassign string_num to this new value
Return results array
=end
The next step was to write an algorithm. My algorithms tend to be too code-y, so I will try to write the algorithm in plain English here.
The first step is to define a method called create_array_of_tiers
that takes a parameter num
. I will initialize a results array and change the given num
into a string. Then, I will use a looping structure to add the string to the front of the array, lob off the last character of the string, and repeat until no more characters are left. Here’s the original, more pseudo-codey version of my algorithm:
=begin
Algo:
initialize a result array, []
initialize lv string_num, assign to the return value of converting a given num to a string
until the string_num is equal to "", prepend string_num to result
remove last character from string_num
- convert to array, remove last character
- call pop on return value of chars called on string, convert back to string, reassign string_num to this new value
Return result array
=end
I ended changing gears in the middle of my coding process because I remembered that pop
returns the last element of the array, so using this method would impede method chaining to convert the array back into a string object.
I decided to use array element reference instead, with an inclusive range up until the second to last character:
def create_array_of_tiers(num)
result = []
string_num = num.to_s
until string_num == ''
result.prepend(string_num)
string_num = string_num.chars[0..-2].join
end
result
end
This works fine, but it seems a little long. I tried refactoring it:
def create_array_of_tiers(num)
result = [num.to_s]
result.prepend(result[0][0..-2]) until result[0].size == 1
result
end
But I don’t like it as much as I like my original code. It seems a little less readable.
I saw some really elegant solutions from other LS students. Vic called map on a range of 1
to the size of the number which then returned a new array containing the return value of string element reference from index 0 to the current length. It was a pretty one-liner, again a little hard to read but quite clever.
def create_array_of_tiers(num)
(1..num.to_s.size).map { |len| num.to_s[0, len] }
end
Marcos used the times method to add each new string to the result array:
def create_array_of_tiers(num)
nummie = num.to_s
result = []
nummie.size.times { |c| result << nummie[0..c] }
result
end
The readability of this one is great. I know exactly what is happening really quickly, even though it has more lines than Vic’s and even though the block parameter c
is a little bit unclear (is it supposed to represent count? I prefer Vic’s len
there). Overall, this is my favorite solution of the four. The #times
method iterates over a range of numbers from 0 to the given number, and it passes each of these numbers to the block, which uses the block parameter c
as in a string element reference call with a range from index 0 to the current number. Really clever.