It’s been a while since I posted this one, but it took a long time to get any responses. So here they are:
Kevin:
# Initialization
alphasArr = ('a'..'z').to_a
alphasArr.sort!
alphas = Hash[*alphasArr.collect { |x| [x, 0] }.flatten]
def printCounts(alphas,text="Counts")
print "\n" + text.to_s + "\n"
alphas.keys.sort.each { |k| print k.to_s + ": " + alphas[k].to_s + " " }
print "\n\n"
end
printCounts(alphas, "Initial Character Counts")
print "Input Data: "
data = Array['all','your','base','are','belong','to','us']
data.each { |x|
print x + " "
x.scan(/./m) { |c| alphas[c] = alphas[c] + 1 }
}
print "\n"
printCounts(alphas, "Counts After Tally")
#notes: this is a bit of a long solution. Let’s talk about what’s going on. the first three lines builds a hash that has the letters a-z as the keys and always a value of 0. the next section defines a function for outputting the data. he then outputs the empty hash, sets the input data, and outputs it as he’s running the tally. finally, he outputs the calculated result.
Let’s spend some time studying this line: alphas = Hash[*alphasArr.collect { |x| [x, 0] }.flatten] as there is a lot going on here. The Hash class has a function [] that allows you to create a new hash by passing in an array in a variety of formats. The simplest of which is ['key', 'value', 'key', 'value'], which is exactly what he’s providing here. Note the * at the beginning of the statement which will expand the result array into a list of params for the [] method.
Also interesting is the use of the scan method to enumerate each character in a string. The built in each_byte method returns an integer, which is hardly what we want here.
there are some shortcuts that can be taken here: in the first section, the sort function can be tacked on to the end of the previous line or probably removed entirely because the range will return the letters in order. The function that increments can be shortened to alphas[c] += 1.
Tim: (I think)
var = {"a"=>0, "b"=>0, "c"=>0, "d"=>0, "e"=>0, "f"=>0, "g"=>0, "h"=>0, "i"=>0, "j"=>0, "k"=>0, "l"=>0, "m"=>0, "n"=
>0, "o"=>0, "p"=>0, "q"=>0, "r"=>0, "s"=>0, "t"=>0, "u"=>0, "v"=>0, "w"=>0, "x"=>0, "y"=>0, "z"=>0 }
open('250_words.txt'){|f| f.readlines}.each {|word| var[word[0,1]] +=1}
var.each {|key, value| print key, " is ", value, "\n" }
Pretty clean. There’s a lot of work being done at the beginning here to setup the hash. Whenever you feel you need to do something as repetitious as this, you’re probably missing something. The function employs a simple one line tally operation that’s based on the work we did for quiz 1. and lastly, some output.
Dave:
letter_counts = Hash.new(0)
open('250_words.txt'){|f| f.readlines}.each{|word| letter_counts[word[0,1]] += 1}
('a'..'z').each{|letter| puts "#{letter}: #{letter_counts[letter]}"}
My solution differs from the previous two in that I never create a full hash with all 26 letters. The constructor for Hash allows you to supply a default value for keys that do not yet exist. In this way, any entry that doesn’t exist will return 0 instead of the default nil. The only tricky part about going this way is the output. I can’t use a simple each because my hash only contains entries for letters that have been used. Instead, I use a range as the basis for my iterator.
All three solutions contain some interesting choices. Can’t wait to see what we come up with next.