Categories
Code challenges Programming

30 Days of Code #1

30 days of code #1: Number to digit tiers, Codewars 7 kyu

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.