FizzBuzz is and old kids games
Not that popular where I am from Brazil, Fizz Buzz has a simple set of rules
You start counting from 1 (obviously) and when a number is a multiple of 3 you say Fizz,
if the number is a multiple of 5 you say Buzz,
and if the number is a multiple of both you shout FizzBuzz,
And for every other case you can say the number itself, simple right?
I watched this really cool video on Tom Scott channel and realized that I have never attempted this problem as a programmer
This is an blog post full of tricks I will try to point them all out.
Naive FizzBuzz
for (i in 1:15){
if(i%%3 == 0 & i%%5 == 0) {
print('FizzBuzz')
}
else if(i%%3 == 0) {
print('Fizz')
}
else if (i%%5 == 0){
print('Buzz')
}
else {
print(i)
}
}
## [1] 1
## [1] 2
## [1] "Fizz"
## [1] 4
## [1] "Buzz"
## [1] "Fizz"
## [1] 7
## [1] 8
## [1] "Fizz"
## [1] "Buzz"
## [1] 11
## [1] "Fizz"
## [1] 13
## [1] 14
## [1] "FizzBuzz"
- Simple flow control with if, else statements
- Some basic operators ($, ==)
Extending the loop approach
Using Scott’s approach we can improve a bit on the logic
for (i in 1:15){
current_out <- ''
if(i%%3 == 0) {
current_out <- paste0(current_out,'Fizz')
}
if (i%%5 == 0){
current_out <- paste0(current_out,'Buzz')
}
if (current_out == ''){
print(i)
}
else print(current_out)
}
## [1] 1
## [1] 2
## [1] "Fizz"
## [1] 4
## [1] "Buzz"
## [1] "Fizz"
## [1] 7
## [1] 8
## [1] "Fizz"
## [1] "Buzz"
## [1] 11
## [1] "Fizz"
## [1] 13
## [1] 14
## [1] "FizzBuzz"
While it is possible to improve open this loop, I think it already is close to the limits of what I would call a very simple example
Functional approach
Thanks Functional FizzBuzz
divisor <-
function(number, string) {
function(d) {
if (d %% number == 0) string else ""
}
}
mod3er <- divisor(3, "Fizz")
mod5er <- divisor(5, "Buzz")
fizzbuzz <-
function(i) {
res <- paste0(mod3er(i), mod5er(i))
ifelse(res == "", i, res)
}
sapply(1:15, fizzbuzz)
## [1] "1" "2" "Fizz" "4" "Buzz" "Fizz"
## [7] "7" "8" "Fizz" "Buzz" "11" "Fizz"
## [13] "13" "14" "FizzBuzz"
So enumerating the new concepts here:
- Functions that create functions (mod3er,mod5er)
- Functions that create functions that create functions (divisor)
- Applying functions (sapply)
- Functional if else (I prefer it)
All of which seen pretty complicated at first but will pay off big time latter.
My approach (tidyverse)
The Basics
Loading the tidyverse
library(tidyverse)
## -- Attaching packages ---------------------------------------------------------------------------------------------------------------------------------------------- tidyverse 1.3.0 --
## <U+2713> ggplot2 3.2.1 <U+2713> purrr 0.3.3
## <U+2713> tibble 2.1.3 <U+2713> dplyr 0.8.3
## <U+2713> tidyr 1.0.0 <U+2713> stringr 1.4.0
## <U+2713> readr 1.3.1 <U+2713> forcats 0.4.0
## -- Conflicts ------------------------------------------------------------------------------------------------------------------------------------------------- tidyverse_conflicts() --
## x dplyr::filter() masks stats::filter()
## x dplyr::lag() masks stats::lag()
divisor <- function(number, string) {
function(input) {
if_else(condition = input %% number == 0,
true = string,
false = "")
}
}
mod3 <- divisor(3, "Fizz")
mod5 <- divisor(5, "Buzz")
list_functions <- list(mod3,mod5)
mapper_list <- function(i,list_functions) map(list_functions, exec,i)
map(1:15,mapper_list,list_functions) %>%
map(reduce,str_c)
## [[1]]
## [1] ""
##
## [[2]]
## [1] ""
##
## [[3]]
## [1] "Fizz"
##
## [[4]]
## [1] ""
##
## [[5]]
## [1] "Buzz"
##
## [[6]]
## [1] "Fizz"
##
## [[7]]
## [1] ""
##
## [[8]]
## [1] ""
##
## [[9]]
## [1] "Fizz"
##
## [[10]]
## [1] "Buzz"
##
## [[11]]
## [1] ""
##
## [[12]]
## [1] "Fizz"
##
## [[13]]
## [1] ""
##
## [[14]]
## [1] ""
##
## [[15]]
## [1] "FizzBuzz"
We learned two new tricks:
- Executing a list of functions using exec
- reducing an list
Making just one call
fancy <- function(i,...) {
list_functions <- list(...)
mapper_list <- function(i,list_functions) map(list_functions, exec,i)
map(i,mapper_list,list_functions) %>%
map(reduce,str_c)
}
fancy(1:15,mod3,mod5)
## [[1]]
## [1] ""
##
## [[2]]
## [1] ""
##
## [[3]]
## [1] "Fizz"
##
## [[4]]
## [1] ""
##
## [[5]]
## [1] "Buzz"
##
## [[6]]
## [1] "Fizz"
##
## [[7]]
## [1] ""
##
## [[8]]
## [1] ""
##
## [[9]]
## [1] "Fizz"
##
## [[10]]
## [1] "Buzz"
##
## [[11]]
## [1] ""
##
## [[12]]
## [1] "Fizz"
##
## [[13]]
## [1] ""
##
## [[14]]
## [1] ""
##
## [[15]]
## [1] "FizzBuzz"
One new trick using ellipsis
Or preparing for an api
api_less_fancy <- function(i,list_functions) {
mapper_list <- function(i,list_functions) map(list_functions, exec,i)
map(i,mapper_list,list_functions) %>%
map(reduce,str_c)
}
api_less_fancy(1:15,list(mod3,mod5))
## [[1]]
## [1] ""
##
## [[2]]
## [1] ""
##
## [[3]]
## [1] "Fizz"
##
## [[4]]
## [1] ""
##
## [[5]]
## [1] "Buzz"
##
## [[6]]
## [1] "Fizz"
##
## [[7]]
## [1] ""
##
## [[8]]
## [1] ""
##
## [[9]]
## [1] "Fizz"
##
## [[10]]
## [1] "Buzz"
##
## [[11]]
## [1] ""
##
## [[12]]
## [1] "Fizz"
##
## [[13]]
## [1] ""
##
## [[14]]
## [1] ""
##
## [[15]]
## [1] "FizzBuzz"
Extending FizzBuzz
Let’s see how easy it is too make the game more difficult:
Changing names
mod3n <- divisor(3, "Buzz")
mod5n <- divisor(5,'Fizz')
fancy(1:15,mod3n,mod5n)
## [[1]]
## [1] ""
##
## [[2]]
## [1] ""
##
## [[3]]
## [1] "Buzz"
##
## [[4]]
## [1] ""
##
## [[5]]
## [1] "Fizz"
##
## [[6]]
## [1] "Buzz"
##
## [[7]]
## [1] ""
##
## [[8]]
## [1] ""
##
## [[9]]
## [1] "Buzz"
##
## [[10]]
## [1] "Fizz"
##
## [[11]]
## [1] ""
##
## [[12]]
## [1] "Buzz"
##
## [[13]]
## [1] ""
##
## [[14]]
## [1] ""
##
## [[15]]
## [1] "BuzzFizz"
Adding divisors
mod2 <- divisor(2, "Deuce")
fancy(1:30,mod2,mod3,mod5)
## [[1]]
## [1] ""
##
## [[2]]
## [1] "Deuce"
##
## [[3]]
## [1] "Fizz"
##
## [[4]]
## [1] "Deuce"
##
## [[5]]
## [1] "Buzz"
##
## [[6]]
## [1] "DeuceFizz"
##
## [[7]]
## [1] ""
##
## [[8]]
## [1] "Deuce"
##
## [[9]]
## [1] "Fizz"
##
## [[10]]
## [1] "DeuceBuzz"
##
## [[11]]
## [1] ""
##
## [[12]]
## [1] "DeuceFizz"
##
## [[13]]
## [1] ""
##
## [[14]]
## [1] "Deuce"
##
## [[15]]
## [1] "FizzBuzz"
##
## [[16]]
## [1] "Deuce"
##
## [[17]]
## [1] ""
##
## [[18]]
## [1] "DeuceFizz"
##
## [[19]]
## [1] ""
##
## [[20]]
## [1] "DeuceBuzz"
##
## [[21]]
## [1] "Fizz"
##
## [[22]]
## [1] "Deuce"
##
## [[23]]
## [1] ""
##
## [[24]]
## [1] "DeuceFizz"
##
## [[25]]
## [1] "Buzz"
##
## [[26]]
## [1] "Deuce"
##
## [[27]]
## [1] "Fizz"
##
## [[28]]
## [1] "Deuce"
##
## [[29]]
## [1] ""
##
## [[30]]
## [1] "DeuceFizzBuzz"
Adding new rules
less <- function(number, string) {
function(input) {
if_else(condition = input < number,
true = string,
false = "")
}
}
less10 <- less(10,"Small")
fancy(1:15,less10,mod3,mod5)
## [[1]]
## [1] "Small"
##
## [[2]]
## [1] "Small"
##
## [[3]]
## [1] "SmallFizz"
##
## [[4]]
## [1] "Small"
##
## [[5]]
## [1] "SmallBuzz"
##
## [[6]]
## [1] "SmallFizz"
##
## [[7]]
## [1] "Small"
##
## [[8]]
## [1] "Small"
##
## [[9]]
## [1] "SmallFizz"
##
## [[10]]
## [1] "Buzz"
##
## [[11]]
## [1] ""
##
## [[12]]
## [1] "Fizz"
##
## [[13]]
## [1] ""
##
## [[14]]
## [1] ""
##
## [[15]]
## [1] "FizzBuzz"
That is it have a great day.