FizzBuzz became popular in the late 2000 – 2010 decade, which was around the same time that may programmers were beginning to rediscover functional programming. I say rediscover rather than discover because functional programming goes back all the way to Lisp, whose spec was written in 1958, which is the dawn of time as far as modern computing is concerned. As Wikipedia puts it, Lisp is “the second-oldest high-level programming language in widespread use today. Only Fortran is older, by one year.”
(Both Fortran and Lisp are heavily based in mathematics — in fact, Fortran is short for FORmula TRANslation. This is one of the reasons that there’s a strong math bias in programming to this day.)
One senior developer I know tested prospective developers’ functional programming skills by issuing this test to anyone who passed the original FizzBuzz test:
Write FizzBuzz, but this time, instead of FizzBuzzifying the numbers 1 through 100, FizzBuzzify the contents of an array, which can contain any number of integers, in any order.
(The senior developer didn’t use the word “FizzBuzzify,” but I think you get my point.)
The resulting app, if given this array…
[30, 41, 8, 26, 3, 7, 11, 5]
…should output this array:
[‘FizzBuzz’, 41, 8, 26, ‘Fizz’, 7, 11, ‘Buzz’]
Note that the original array contained all integers, while the result array can contain both strings and integers. The senior developer was interviewing programmers who’d be working in Ruby, where you can easily use arrays of mixed types.
You’d get a passing grade if your solution simply adapted the original FizzBuzz to take an array as its input. Here’s a Python implementation of that solution:
def fizzBuzz_list_imperatively(numbers):
finalResult = []
for number in numbers:
currentResult = None
isMultipleOf3 = (number % 3 == 0)
isMultipleOf5 = (number % 5 == 0)
if isMultipleOf3 and isMultipleOf5:
currentResult = "FizzBuzz"
elif isMultipleOf3:
currentResult = "Fizz"
elif isMultipleOf5:
currentResult = "Buzz"
else:
currentResult = number
finalResult.append(currentResult)
return finalResult
However, the developer was looking for a more functional approach. In functional programming, if you’re being asked to perform some kind of calculation based on the contents of a list, you should probably use a map, filter, or reduce operation.
In case you’re not quite familiar with what these are, here’s a simple explanation that uses emojis:
Much nicer than a dry textbook explanation, isn’t it?
The map operation, given a list and a function, applies that function to every item in the given list, which creates a new list. The senior developer granted bonus points to anyone who came up with a map-based solution.
Here’s a Python implementation of what the senior developer was looking for:
This implementation breaks the problem into two functions:
A fizzBuzzify() function, which given a number, returns Fizz, Buzz, FizzBuzz, or the original number, depending on its value, and
A map() function, which applies fizzBuzzify() across the entire array.
Remember, the senior developer was looking for Ruby developers, and Ruby doesn’t support nested functions. Python does, however, and I like packaging things neatly to prevent errors. I think that if a function a makes exclusive use of another function b, you should nest b inside a.
With that in mind, let’s update fizzBuzz_list_functionally():
Sooner or later, you will encounter — or worse still, end up working with — a programmer who only seems good at programming. This person will have an impressive-looking resume. They’ll know all the proper terminology, be able to speak intelligently about the key concepts in this programming language or that framework or library, and may even have given a pretty good talk at a meetup or conference. But when they’re put to the task of actually writing working software, they just can’t do it.
These aren’t programmers who have difficulty taking on big problems, such as the kind you run into when working on complex problems and writing all-new code from scratch. They’re not even programmers who run into trouble just working on the sort of everyday problems that you encounter maintaining established, working software. These are programmers who can’t solve simple problems, the sort that you should be able to do during a lunch or coffee break. They might be good in other roles in the development process, but not in one where they have to write production code.
As a result, there’s a category of little assignments whose sole purpose isn’t to identify great programmers, or even good ones, but to spot the ones you shouldn’t hire. The best known of these is the dreaded FizzBuzz.
Most good programmers should be able to write out on paper a program which does this in a under a couple of minutes.
Want to know something scary ? – the majority of comp sci graduates can’t. I’ve also seen self-proclaimed senior programmers take more than 10-15 minutes to write a solution.
I’m not saying these people can’t write good code, but to do so they’ll take a lot longer to ship it. And in a business environment that’s exactly what you don’t want.
Let’s look at a couple of Python implementations.
The dumb-as-a-bag-of-hammers solution
If you think your interviewer has a sense of humor, you might try throwing this solution at them. I put this in a file named fizzbuzz.py:
Note that I wrote this as a function that returns a string instead of as just a print statement. There’s a reason for this — as a function, it’s testable.
Let’s create a file for FizzBuzz tests. I called mine test_fizzbuzz.py. It’s also pretty dumb — all it does it confirm that fizzBuzzDumb() spits out the right result. It’s pretty much guaranteed to pass, since I copied and pasted the string from fizzBuzzDumb() into the constant that the test uses to confirm that the output is correct:
With fizzbuzz.py and test_fizzbuzz.py in hand, I ran the test, and it unsurprisingly passed:
Working towards a real solution
The multiple problem
The first stumbling block I’ve seen people trying to write FizzBuzz is that they have no idea how to tell if a number x is a multiple of some other number y. This happens particularly often when the programmer doesn’t come from a math background.
(There’s a bit of math snobbery and bias in classical computer science. Some of it is just general academic snobbery, and some of it is from the fact that computer science wasn’t originally its own field of study in universities, but often a branch of the math or engineering department.)
To solve this problem, you want to use the modulo operator — the % symbol. It performs integer division, but instead of giving you the quotient (the result of a division), it gives you the remainder.
For example 3 % 2 gives you a result of 1. That’s because after dividing 3 by 2, you get a remainder of 1. 5 % 2 also gives you a result of 1, because 2 goes into 5 twice, leaving you a remainder of 1. 9 % 5 gives you a result of 4, as 5 goes into 9 once, leaving a remainder of 4.
If a division operation results in no remainder, % returns a result of 0. For instance 2 % 2, 4 % 2, 6 % 2, 8 % 2, and 10 % 2 all return a result of zero, since they’re all even numbers, which are all evenly divisible by 2. Another way of putting it is to say that they’re multiples of 2.
With this in mind, we can easily come up with a couple of statements that test if a number is a multiple of 3 and if a number is a multiple of 5:
At the end of this if statement, currentResult contains one of the following: FizzBuzz, Fizz, Buzz, or a number.
When live-coding in front of an audience — which is pretty much what a technical interview is — you want to keep a couple of things in mind:
You want to use the code to communicate your intent to the audience as clearly as possible.
Complexity is your enemy. You want to make the simplest thing that works.
My approach was to do handle the trickiest case first. My if statement handles the case where the number is both a multiple of 3 and a multiple of 5 first, followed by the individual multiple cases, followed by the default case. It’s simple, it’s easy to follow, and best of all, it works.
Putting it all together
Here’s the fizzBuzz() function that I wrote. I put it in fizzbuzz.py, just after the definition of fizzBuzzDumb():
def fizzBuzz(first = 1, last = 100):
finalResult = ""
for number in range(first, last + 1):
currentResult = ""
isMultipleOf3 = (number % 3 == 0)
isMultipleOf5 = (number % 5 == 0)
if isMultipleOf3 and isMultipleOf5:
currentResult = "FizzBuzz"
elif isMultipleOf3:
currentResult = "Fizz"
elif isMultipleOf5:
currentResult = "Buzz"
else:
currentResult = str(number)
finalResult += currentResult
if number < last:
finalResult += ", "
else:
finalResult += "."
return finalResult
Greetings, Tampa Bay techies, entrepreneurs, and nerds! Welcome to the June 15, 2020 edition of the list! Here’s this week’s list of online-only events for techies, entrepreneurs, and nerds based in an around the Tampa Bay area. Keep an eye on this post; I update it when I hear about new events, it’s always changing. Stay safe, stay connected, and #MakeItTampaBay!
Suncoast Developer Group’s Summer 2020 Hackathon: Friday to Sunday
Don’t forget that Suncoast Developers Guild is holding an online Summer Solstice Hackathon this coming weekend! It starts on the afternoon of Friday, June 19th and runs through Sunday the 21st. As they put it, it’s an opportunity to “spend the longest day of the year solving the hardest challenges of 2020 with fellow developers, designers, and champions of economic development in our region.”
There will be three key themes for this hackathon:
Pandemic preparedness and recovery: Every day in this region, software developers are solving problems for non-profits, businesses, families, and communities. As COVID-19 has shown us, this recovery depends on solving problems in creative ways. How can we best be prepared for the next pandemic?
Inclusion, diversity, and intersectionality in the tech workforce:Yes, Houston, we have a problem. When a workforce does not represent the communities it serves, it causes harm and hampers vibrant solutions. SDG’s is working to change this; come and help us.
Building a smarter, more connected Tampa Bay: Developers understand both sustainability and problem-solving. Harness our power by solving a Smart City challenge that will elevate us all. Can we build IoT and Smart City solutions that help our region’s residents without hurting their privacy?
There will be three cash prizes for each theme: $1000 for the main prize, $750 for the runner-up, and $250 for the solo participant. That’s nine prizes in total!
Once again, this event will happen online. You can hack in the comfort of your own home — all hanging out will be done on Discord. Registration and participation is free-as-in-beer.
Do you have an upcoming event that you’d like to see on this list?
If you know of an upcoming event that you think should appear on this list, please let me know!
Join the mailing list!
If you’d like to get this list in your email inbox every week, enter your email address below. You’ll only be emailed once a week, and the email will contain this list, plus links to any interesting news, upcoming events, and tech articles.
Join the Tampa Bay Tech Events list and always be informed of what’s coming up in Tampa Bay!
Oh hey — why not one more? In the past three articles, I’ve been writing about a challenge that’s often given to programmers at a tech interview: Write a program that determines if two words are anagrams.
In the first article, I wrote a basic Python solution. In the second article, I refined the Python solution and then based a JavaScript solution on it. In the third article, I showed a couple of Swift implementations — one simple, one hardcore. In this article, I’ll present Ruby and C# solutions.
The Ruby version
I used to work with Ruby and Rails a fair bit, so I really should post a Ruby version:
def sortLetters(word)
word.downcase.chars.sort.join.strip
end
def anagram?(word1, word2)
sortLetters(word1) == sortLetters(word2)
end
# Let’s try it out
puts anagram?('iceman', 'cinema') # true
puts anagram?('Florida', 'fail rod') # true
puts anagram?('ABC', 'xyz') # false
Some things to note:
Ruby doesn’t support nested methods. You can put a method inside another method in Ruby, but that doesn’t make it a nested method. That’s why I’ve defined sortLetters() and anagram?() as two separate methods.
I wrote these methods to reflect the preferred “delightfully terse” style that is preferred way in the Ruby world. InsortLetters(), and I skip the return statement (optional in Ruby; in its absence, a method returns the result of its last line), use method chaining, and skip any unnecessary parentheses, hence word.downcase.chars.sort.join.strip, which very clearly states that it does the following:
Convert the given string to all lowercase characters.
Split the resulting string into an array of characters.
Sort the array.
Turn the array back into a string.
Strip any leading and trailing strings from string. If the original string had any spaces in it, they would be leading spaces in the current string.
Following Ruby convention, I added a ? to the “anagram” name to make the name of the method anagram?(), which is the Ruby convention for methods that return boolean values. As with the versions of anagram()that I wrote in JavaScript, Python, and Swift, two words are anagrams of each other if their sorted forms are the same.
If you’re interested in trying the histogram approach, you may want to try out Ruby’s Enumerable#tally method:
'foo'.chars.tally # results in {"f"=>1, "o"=>2}
The C# version
Here’s the C# version. It uses LINQ, because LINQ often makes life easier:
In the past two articles, I’ve been writing about a challenge that’s often given to programmers at a tech interview: Write a program that determines if two words are anagrams.
In the first article, I wrote a basic Python solution. In the second article, I refined the Python solution and then based a JavaScript solution on it. In this article, I’ll present a couple of Swift solutions.
A simple Swift solution
Here’s a Swift solution that follows the same logic as the Python and JavaScript solutions I presented in the previous article:
The Swift version of anagram() takes the same approach as the Python and JavaScript version by making use of a function named sortLetters(in:) that sorts the letters of a string in place. Here’s what it does:
It takes the given word — stored in the parameter word — and converts it to all lowercase letters using String’s lowercased() method.
The all-lowercase word is converted into a sorted array of Characters by String’s sorted() method.
The sorted array of Characters is converted back into a string using String’s initializer.
Any leading whitespace in the string (the result of sorting a String with spaces in it) is removed with String’s trimmingCharacters(in:) method.
Once sortLetters(in:) is defined, all anagram() has to do is apply it to both words and see if the results are the same.
Jessy Catterwaul’s hardcore Swift solution
When something about Swift confuses me (it happens!) my go-to person is Jessy Catterwaul, video course creator at raywenderlich.com (where I’m an author). His approach to the anagram problem was to use histograms and bucketing — or in simpler terms, to use a data structure to store the counts of each letter in both words. If both words have the same number of the same letters, they’re anagrams of each other.
He sent me this code, which defines an extension for Swift’s Dictionary class. It gives Dictionary a new initializer method, init(bucketing:). If you provide this initializer with a string, it creates a dictionary whose keys are the letters in the string, and whose corresponding values are the counts of those letters. For example, if you provide the initializer with the string abbccc, it returns a the dictionary ["a": 1, "b": 2, "c": 3].
Here’s the code:
public extension Dictionary where Value == Int {
/// Create “buckets” from a sequence of keys,
/// such as might be used for a hsitogram.
init<Keys: Sequence>(bucketing unbucketedKeys: Keys)
where Keys.Element == Key {
self.init(
zip(unbucketedKeys, AnyIterator { 1 }),
uniquingKeysWith: +
)
}
}
Once the extension is defined, the following code…
let mississippiLetterCount = Dictionary(bucketing: "Mississippi")
print("Mississippi letter count: \(mississippiLetterCount)")
Next week, I’ll showcase another programming challenge that I’ve seen in technical interviews: The dreaded FizzBuzz! I’ll also devote some time to covering the “why” of programming challenges.
Previously, in the “Programmer interview challenge” series
Looking at the code for anagram(), it’s quite clear that it isn’t DRY (Don’t Repeat Yourself), but manifestly the opposite: WET (Write Everything Twice)!
Under the time constraints of a technical interview, you might not always have the time or cognitive bandwidth to keep your code DRY, but if you should try to do so if possible. You may find that it helps convey your algorithmic thinking more effectively to the interviewer, and that’s what you want. After all, your goal throughout the process is to prove that you can actually program.
The repeated code is the part that takes a string, sorts its characters into alphabetical order, and removes the leading space if it exists. Let’s turn that code into its own method:
def sortLetters(word):
# Returns the given word with its letters sorted
# into alphabetical order and with any
# leading space removed.
word_lowercase = word.lower()
return ''.join(sorted(word_lowercase)).lstrip()
With this method defined, we can use it in anagram(). In fact, we can nest it within anagram(). Here’s the revision:
def anagram(first_word, second_word):
# Returns True if the given words are made of the exact same characters,
# ignoring capitalization and spaces.
def sortLetters(word):
# Returns the given word with its letters sorted
# into alphabetical order and with any
# leading space removed.
word_lowercase = word.lower()
return ''.join(sorted(word_lowercase)).lstrip()
return sortLetters(first_word) == sortLetters(second_word)
Creating the sortLetters() method doesn’t just DRY up the code, but helps the method better convey what it does. Now, what anagram() does is very clearly conveyed by its return statement: it tells you if the first word with its letters sorted is the same as the second word with its letters sorted.
I confirmed that this refactored code works by running the tests, which show just how useful having tests is.
Implementing anagram() in JavaScript
Here’s anagram() in JavaScript:
function anagram(firstWord, secondWord) {
function sortLetters(word) {
return word
.toLowerCase()
.split('')
.sort()
.join('')
.trim()
}
return sortLetters(firstWord) === sortLetters(secondWord)
}
Note that the JavaScript version of sortLetters() is structured slightly differently from the Python version. That’s because JavaScript’s sort() is an array method rather than a general function like Python’s sorted().
In the JavaScript version of sortLetters(), I use method chaining to spell out what happens to the given word step by step:
Convert the word to lower case
Convert that into an array of characters
Sort that array
Convert that array into a string
Remove any trailing or leading whitespace
I could’ve written sortLetters() this way…
function sortLetters(word) {
return word.toLowerCase().split('').sort().join('').trim()
}
…but I find that “put each method in the chain on its own line” approach more clearly conveys what I’m trying to do:
function sortLetters(word) {
return word
.toLowerCase()
.split('')
.sort()
.join('')
.trim()
}
Next: The Swift version!
Previously, in the “Programmer interview challenge” series
An anagram is a word, phrase, or name that can be formed by rearranging the letters in another word, phrase, or name. For example, iceman is an anagram of cinema, and vice versa. Ignoring spaces and capitalizations, “Florida” is an anagram of “rod fail”.
“Anagram” is a common programming challenge that I’ve seen issued to prospective developers in technical interviews: Write a program or function that can tell if two given words are anagrams of each other. Here’s how you solve it.
The general idea
One solution to the problem is hinted at in the definition of “anagram”. Let’s look at it again:
An anagram is a word, phrase, or name that can be formed by rearranging the letters in another word, phrase, or name.
The word rearranging should be your hint. Somehow, the solution should involve rearranging the letters of both words so that you can compare them. Another word for rearranging is reordering, and when you encounter that word in programming, you should think of sorting. That’s where the solution lies:
If two words are anagrams of each other, sorting each word’s letters into alphabetical order should create two identical words. For example, if you sort the letters in cinema and iceman into alphabetical order, both will be turned into aceimn.
With that in mind, let’s try writing an anagram-detecting function. Given two strings, it should return true if they’re anagrams of each other, and false otherwise.
To run the test, enter pytest at the command line. You should see output that looks like this:
Now that we have a failing test, let’s write code to make it pass.
Sorting the letters in a string is Python can be done by using a couple of methods:
sorted(), which when given a string, returns an array containing that string’s letters in ascending order. For example, sorted('cinema') returns ['a', 'c', 'e', 'i', 'm', 'n'].
join(), which when given a string and an array, returns a string where the elements of the array are joined by the given string. For example, '*'.join(['a', 'b', 'c']) returns 'a*b*c'.
Let’s now deal with cases with capitalization and spaces. Ideally, the anagram() method should treat “Florida” and “rod fail” as anagrams. We’ll specify this in the test:
import pytest
from anagram import anagram
def test_simple_anagram():
assert anagram('iceman', 'cinema'), "'cinema' is an anagram of 'iceman'."
def test_complex_anagram():
assert anagram('Florida', 'rod fail'), "'rod fail', if you ignore spaces and capitalization, is an anagram of 'Florida'."
Running pytest yields these results: 1 failed test and 1 passed test…
We can fix this through the use of another two methods:
lower(), which when applied to a string, converts all its letters to lowercase. For example, 'RADAR'.lower() returns 'radar'.
lstrip(), which when applied to a string, removes any whitespace characters from the left side. Since the space character has a lower value than any letter in the alphabet, it will always be the leftmost character in a string whose characters have been sorted into ascending order.
Just to be safe, let’s add a test to make sure than anagram() returns False when given two strings that are not anagrams of each other:
import pytest
from anagram import anagram
def test_simple_anagram():
assert anagram('iceman', 'cinema'), "'cinema' is an anagram of 'iceman'."
def test_complex_anagram():
assert anagram('Florida', 'rod fail'), "'rod fail', if you ignore spaces and capitalization, is an anagram of 'Florida'."
def test_non_anagram():
assert anagram('ABC', 'xyz') == False, "'ABC' and 'xyz' are not anagrams."
All test pass when pytest is run:
And trying all sorts of pairs of strings confirms what the test tells us: anagram() works!
# All of these return True
anagram('Oregon', 'no ogre')
anagram('North Dakota', 'drank a tooth')
anagram('Wisconsin', 'cows in sin')
# All of these return False
anagram('Florida', 'i oil sauna') # Try Louisiana
anagram('New York', 'on my wig') # Try Wyoming
anagram('Georgia', 'navy sin panel') # Try Pennsylvania
…and there you have it!
Next: Implementing anagram() in JavaScript, Swift, and possibly other languages.