FizzBuzz One-Liner In Perl
Write one-liner to solve FizzBuzz problem and print number 1-20. However, any number divisible by 3 should be replaced by the word fizz and any divisible by 5 by the word buzz. Numbers divisible by both become fizz buzz.
It’s a common one, and my all-time favorite solution begins with:
import numpy as np
import tensorflow as tf
But there’s a word in there that changes everything.
“one-liner”
A one-liner is code that is typed in at the prompt, in the form perl -e '[CODE GOES HERE]'
. It doesn’t have to be Perl – for example try this with Node: node -p '0.1 + 0.2'
– but Perl borrowed a lot from sed
and awk
, which are meant to be used in this way.
This word brings me chills, because “one-liner” tends toward Perl Golf, and Perl Golf tends toward solutions that are oblique, indecypherable and unmaintainable.
Everyone knows that debugging is twice as hard as writing a program in the first place. So if you’re as clever as you can be when you write it, how will you ever debug it? – Brian Kernighan
So, I asked for clarification, and no, we’re wanting an elegant solution. Shub-Internet suggests elegant means (of a scientific theory or solution to a problem) pleasingly ingenious and simple, so let’s get simple!
#!/usr/bin/env perl
use strict;
use warnings;
for my $i ( 1 .. 20 ) {
if ( $i % 3 == 0 && $i % 5 == 0 ) { print 'fizzbuzz' }
elsif ( $i % 3 == 0 ) { print 'fizz' }
elsif ( $i % 5 == 0 ) { print 'buzz' }
else { print $i }
print "\n";
}
Here we’re not holding onto flags or anything. Just one variable, $i
. I defend the elegance of this code because there’s four cases: divisible by 3, divisible by 5, divisible by both, and divisible by neither.
This covers all four cases, but we can get simpler.
#!/usr/bin/env perl
use strict;
use warnings;
for my $i ( 1 .. 20 ) {
if ( $i % 3 == 0 ) { print 'fizz' }
if ( $i % 5 == 0 ) { print 'buzz' }
if ( $i % 3 != 0 && $i % 5 != 0 ) { print $i }
print "\n";
}
Quick Note:
%
ismodulus
, which isn’t a thing you’re taught until you start with computing. It’s basicallyremainders
. Consider10 / 3
, which equals3.3333333...
.10 % 3
is essentially10 - (3*3)
, or1
.9 - (3 * 3)
is0
. If you don’t have a CS background, this makes up for a month of CS 101.
I don’t like the $i % $n == 0
test, and I think we can get better. I had tried ! $i % $n
, but that didn’t behave for me, so I’m thinking ternary operators. For those who don’t know, we can take:
if ( $i % 3 ) { print '' }
else { print 'fizz' }
and replace it with
print $i % 3 ? '':'fizz';
This is not a Perlism; it exists in many languages.
Quick Note: Here, we are playing with truth. Within conditionals,
false
means0
andtrue
meansnot 0
. With%3
, we can get the values0
,1
, and2
, and both1
and2
count astrue
. That’s another free week of CS 101, and a little bit of Boolean for PHIL 131 - Introduction to Logic.
Using the ternary operator, we can get down to:
#!/usr/bin/env perl
use strict;
use warnings;
for my $i ( 1 .. 20 ) {
print $i % 3 ? '':'fizz';
print $i % 5 ? '':'buzz';
print $i % 3 && $i % 5 ? $i : '';
print "\n";
}
That’s … okay, but still not something I would type out.
So we drop the strictures. I will not make a program that does not start out with use strict; use warnings;
but one-liners are different. Those can be ejected, and with it, my
. And, also, $i
;
perl -e 'for (1..20) { print ; print "\n" }'
This gives us that range, because unless we designate a variable, it’s $_
. Read perlvar
for more details.
A thing to remember is that we’re hitting on a point where both your shell and Perl have opinions about single-quotes and double-quotes. Perl allows you to replace 'foo'
with q{foo}
, and "bar"
with qq{bar}
, but we won’t be doing that here.
$ perl -e 'for (1..20) { print $_ % 3 ? "" : "fizz" ; print $_ % 5 ? "" : "buzz" ; print $_ % 3 && $_ % 5 ? $_ : "" ; print "\n" }'
1
2
fizz
4
buzz
fizz
7
8
fizz
buzz
11
fizz
13
14
fizzbuzz
16
17
fizz
19
buzz
I have been informed that perl -E
gives you all the features that have been added during the time of Modern Perl, which in this case, would allow me to swap print "\n"
with say ""
, which I don’t regard as a big difference. Good to know in the future, because I love say
, but in this case, macht nicht.
If I was more of a code golfer, I could probably make that more terse, but as is, I think this is elegant and readable, which is as good as a one-liner can be.
Now, what can I do with node -e
?
If you have any questions or comments, I would be glad to hear it. Ask me on Twitter or make an issue on my blog repo.