Latest Ruby Quiz:
====================================================================
There has been some debate on the proper ways to screen programmers
you intend
to hire.  A common theory is that you really need to have the
programmer write
some code for you to accurately gauge their skill.  Exactly what to
have them
write is another debate, but the blogosphere has recently been abuzz
with this
question as a screener:

       Write a program that prints the numbers from 1 to 100.
       But for multiples of three print "Fizz" instead of the
       number and for the multiples of five print "Buzz". For
       numbers which are multiples of both three and five
       print "FizzBuzz".

Pretend you've just walked into a job interview and been hit with this
question.
Solve it as you would under such circumstances for this week's Ruby Quiz.
====================================================================

**** From:  Daniel Martin -- [EMAIL PROTECTED]
------------------------------------------------
# Well, Mr. Martin, this is just a simple little question we ask all of
# our programming candidates.  Let's see what you do with "FizzBuzz":

(1..100).each{|i|
 x = ''
 x += 'Fizz' if i%3==0
 x += 'Buzz' if i%5==0
 puts(x.empty? ? i : x);
}

# Okay, very straightforward.  You know, I've never been an overly big
# fan of the question mark-colon operator.  It always seemed to me one
# of the constructs in C most open to abuse.
#
# What's that?  Oh, okay, so how would you eliminate that ?: in favor
# of something more Rubyish?

(1..100).each{|i|
 x = i
 x = 'Fizz' if i%3==0
 x += 'Buzz' if i%5==0 rescue x='Buzz'
 puts x;
}

# Well using "rescue" certainly does feel more Rubyish.
#
# It says here that you've done significant work with functional
# languages.  Could you rewrite this to take advantage of higher order
# functions?

a = [proc{|x|x}, proc{|x|x}, proc{:Fizz}] * 5
a[4]=a[9]=proc{:Buzz}
a[14]=proc{:FizzBuzz}
(1..100).zip(a*9){|i,l|puts l[i]}

# Well that's rather cryptic, and I don't necessarily like the manual
# computation behind the indexes 4, 9, and 14.  I'd prefer something
# that, like your first two solutions, combined the Fizz and Buzz so
# that the FIzzBuzz printed every fifteen spots is a natural
# consequence.

f = proc{'Fizz'}
b = proc{|x|x+'Buzz' rescue :Buzz}
i = proc{|x|x}
(1..100).zip([i,i,f]*99,[i,i,i,i,b]*99){|n,p,q|puts q[p[n]]}

# Uh... yes.  In that I can see the two cycles, the 3-cycle and the
# 5-cycle, but I'm not sure that turned out as clear as I had hoped.
#
# I wonder if a hybrid approach where you used anonymous functions
# only for one of the two words is worth considering...

b=proc{|i,s|i%5==0?s+'Buzz':s rescue :Buzz}
puts (1..100).map{|i|b[i,i%3==0?'Fizz':i]}

# There's that ?: operator again.
#
# You know, you aren't really using arbitrary functions there.  I wonder
# if lambda functions aren't overkill for this problem.  What if you
# repeated the pattern where you showed the two cycles, but used simple
# strings instead?

$;='/'
(1..100).zip('//Fizz'.split*99,'////Buzz'.split*99) {|a|
puts(('%d%s%s'%a).sub(/\d+(?=\D)/,''))}

# Well, okay, you've shown that sometimes strings are not as easy to read
# as one might think.
#
# I noticed you using a regular expression there and I note that your
# resume shows extensive experience with regular expressions.  That's a
# rather small example on which to judge your regular expression
# experience.  Could you somehow make more use of regular expressions?

(1..100).map{|i|"#{i}\n"}.join.
 gsub(/^([369]?[0369]|[147][258]|[258][147])$/m,'Fizz\1').
 gsub(/\d*[50]$/m,'Buzz').gsub(/z\d+/,'z').display

# Let us never speak of this again.
#
# Well, Mr. Martin, I think you've shown technically what we're looking
# for.  Tell me, do you golf?

puts (1..100).map{|a|x=a%3==0?'Fizz':'';x+='Buzz'if a%5==0;x.empty?? a:x}

# Uh, that

puts (1..100).map{|i|[i,:Buzz,:Fizz,:FizzBuzz][i%5==0?1:0+i%3==0?2:0]}

# Mr. Martin, that's not

puts (1..100).map{|i|i%15==0?:FizzBuzz:i%5==0?:Buzz:i%3==0?:Fizz:i}

# I, uh, hadn't meant that kind of golf.
# (Though, as an aside, you could save characters by using 1.upto(100)
#  and by using <1 in place of ==0)
#
# However, these last few examples bring home a point I was worrying about
# before that we haven't really touched on yet - all of these have
# varying degrees of readability, yet Ruby is supposed to be an eminently
# readable language.  How could you make this code more readable?

puts (1..100).map{|i|
 case i%15
 when 0        then :FizzBuzz
 when 5,10     then :Buzz
 when 3,6,9,12 then :Fizz
 else i
 end
}

# Well, that certainly is an improvement, though separating the "puts"
# from the rest of the logic might be slightly confusing and I'd prefer
# a more direct translation from the English program specification to
# the code.

(1..100).each {|i|
 if    i%5==0 and i%3==0 then puts :FizzBuzz
 elsif i%5==0            then puts :Buzz
 elsif            i%3==0 then puts :Fizz
 else                         puts i
 end
}

# Well now.
#
# Okay, are there any other tricks you have to show before we wrap this
# up?

h=Hash.new{|d,k|k>14?h[k%15]:nil}
h[0]=:FizzBuzz
h[3]=h[6]=h[9]=h[12]=:Fizz
h[5]=h[10]=:Buzz
puts (1..100).map{|i|h[i]||i}

# That looks rather familiar and similar to your first anonymous function
# solution.  I think we've both had enough of this problem by now.
#
# Well, it's been nice talking to you, Mr. Martin, and I thank you for
# your interest in CompuGlobalMegaTech.  We'll be in touch over the next
# few days with our decision.


--
s=%q(  Daniel Martin -- [EMAIL PROTECTED]
      puts "s=%q(#{s})",s.to_a.last       )
      puts "s=%q(#{s})",s.to_a.last



Reply via email to