Sunday, December 28, 2014

Hash class, pretty formatting with printf

I went back tonight to finish up some Ruby file IO practice via the following tutorial:

http://tutorials.jumpstartlab.com/projects/eventmanager.html

I'd finished everything except the last few sections, which eschew the handholding and ask you to clean up phone number, date and time data and generate report files after manipulating it.

As I put the finishing touches on my code, I took a gander at another student's work and was dumbfounded by how much smarter it was than mine. Cleaner, quicker, and easier to read. I felt like an herbal remedy peddler from a lost civilization who'd suddenly been exposed to an open-heart surgery-- why even bother with what I've been doing? That's just better.

So I borrowed some ideas. Not the code itself, mind you.

The biggest thing I picked up was how to quickly generate hashes to keep track of how many of something you have. For example, let's generate a hash to count up how many of each character (case-insensitive) the following sentences contain: "I'm gonna get measured! Hope I measure up!"

To this point I'd been doing the following:

str = "I'm gonna get measured! Hope I measure up!"
hash = {}
str.split('').each do |char|
  char.downcase!
  if hash[char] == nil
    hash[char] = 1
  else
    hash[char] += 1
  end
end


Which is silly, evidently, because I saw the open-heart-surgeon doing it like this:

str = "I'm gonna get measured! Hope I measure up!"
hash = Hash.new(0)
str.split('').each {|char| hash[char.downcase] += 1}

Much better. Frankly I'm not sure why you can do the latter this way-- you'd be subjected to an "undefined method '+' for nil:NilClass" NoMethodError if you tried to add to a hash value for which the key didn't exist in the former code.

Must either be because an instance variable of the Hash class is somehow different from a hash defined as {}, or because of the zero that's given as an argument when making the new hash via Hash.new(0)**

Also, in an effort to get the data formatted nicely I came across the following Stackoverflow question/answer:

http://stackoverflow.com/questions/1087658/nicely-formatting-output-to-console-specifying-number-of-tabs

To align two columns of text nicely, you can use the following command:

printf "%-20s %s\n", string1, string2

The -20 means that the first string (signified by %s here) will occupy 20 characters; whitespace will be used to cover ground that isn't occupied by its actual letters. The minus sign means that the letters will be placed in the beginning of this string, followed by its whitespace, covering 20 characters in total.

If we entered "%20" instead (no minus sign), the letters would come last, being preceded by whitespace. After this 20-character string, we'll have another space, and then the second string.

i.e.

$ printf "%-20s %s\n", "howdy", "y'all"

howdy                y'all

$ printf "%20s %s\n", "howdy", "y'all"

               howdy y'all


...You can change the number, naturally. I'd imagine that you can also add more strings by adding more "%s"s and their alignments, but I haven't tried it yet.

Here's my code!

https://github.com/johnwquarles/jumpstartlab-event-manager

** as of 1/24/2015 I do know why; Michael Hartl's Rails tutorial explains this very point toward the bottom of section 4.4.1. "Hash.new takes a default value for the hash, which is the value of the hash for a nonexistent key." So in the code above, the hash returns zero for nonexistent values, instead of nil, which you can't add to.

No comments:

Post a Comment