Vectorize everything with Julia. Say goodbye to for loops and broadcast... | by Bence Komarniczky | Towards Data Science

Do you ever feel like for loops are taking over your life and there’s no escape from them? Do you feel trapped by all those loops? Well, fear not! There’s a way out! I’ll show you how to do the FizzBuzz challenge without any for loops at all.
The task of FizzBuzz is to print every number up to 100, but replace numbers divisible by 3 with “Fizz”, numbers divisible by 5 by “Buzz” and numbers that are divisible by both 3 and 5 have to be replaced by “FizzBuzz”.
Solving FizzBuzz with for loops is easy, you can even do this in BigQuery. Here, I’ll show you an alternative way of doing this — without any for loops whatsoever. The solution is Vectorised Functions.
If you already had some experience with R and Python, you’ve probably already come across vectorised functions in standard R or via Python’s numpy library. Let’s see how we can use them in Julia similarly.
Vectorised functions are great as they reduce the clutter often associated with for loops.
Before we dive into solving FizzBuzz let’s see how you can replace a very simple for loop with a vectorized alternative in Julia.
Let’s start with a trivial task: Given a vector a add 1 to each element of it.
julia> print(a)[2, 3, 4]
The above gets the job done, but it takes up 3 lines and a lot more characters than needed. If a was a numpy array in Python 🐍, you could just do a + 1 and job done. But first, you would have to convert your plain old array to a numpy array.
Julia has a clever solution. You can use the broadcast operator . to apply an operation — in this case, addition — to all elements of an object. Here it is in action:
Even better than that, you can broadcast any function of your liking, even your own ones. Here we calculate the area of a circle and then we broadcast it across our array:
julia> area_of_circle.(a)3-element Array{Float64,1}:  3.141592653589793 12.566370614359172 28.274333882308138
Now that we know the basics, let’s do FizzBuzz! But remember, no for loops allowed.
We will rephrase our problem a little bit. Instead of printing the numbers, Fizzes and Buzzes, we’ll return all of them together as a vector. I’ll break down the solution the same way as in the for loop article [LINK], so if you haven’t seen the previous posts, now would be a good time to check it out!
First, let’s return the numbers up until nas a vector:
julia> fizzbuzz(5)5-element Array{Int64,1}: 1 2 3 4 5
This works. Let’s see if we can print Fizz for each number that’s divisible by 3. We can do this by replacing all numbers that are divisible by 3 with a Fizz string.
julia> fizzbuzz(7)7-element Array{String,1}: "1" "2" "Fizz" "4" "5" "Fizz" "7"
Let’s break this down step by step:
Why did we replace everything with string? Well, the array of numbers are just that, an array of numbers. We don’t want to have numbers and strings mingled up in a single object.
We broadcast rem.(numbers, 3 to find the remainder of all the numbers.
Then we compared this array of remainders elementwise to 0 ( .== 0 ).
Finally, we indexed our string array with the boolean mask and assigned “Fizz” to every element where our mask says true.
Feel free to break these steps down and try them in your own Julia REPL!
I know that the use of .= to assign a single element to many can be a bit controversial, but I actually quite like it. By explicitly specifying the broadcast of assignment you force yourself to think about the differences of these objects and everyone who reads your code afterwards will see that one is a vector and the other one is a scalar.
Adding the Buzzes is done exactly the same way:
No comment on this one. 😃
All we’re missing are the FizzBuzz elements for numbers divisible by both 3 and 5.
We used .*to “multiply” two boolean arrays. You can think of * as a boolean andin this case. So this gives us a true value where the numbers are divisible by both 3 and 5.
Let’s see if this all works:
julia> fizzbuzz(16)16-element Array{String,1}: "1" "2" "Fizz" "4" "Buzz" "Fizz" "7" "8" "Fizz" "Buzz" "11" "Fizz" "13" "14" "FizzBuzz" "16"
The above certainly does what we want, but it’s not exactly the prettiest. Time to tidy up and make our code nice and presentable.
This achieves exactly the same as above, but it’s a lot easier to read. We find the indexes that we want to replace and then we replace our array elements where needed. We also used % instead of the rem function, because if there’s an operator for your function, then you should use it!
After reading this article, you now know how to broadcast any function in Julia using . and make your code more readable by removing some of the unnecessary for loops.
For full access to all Medium articles — including mine — consider subscribing here.