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.

Vectorize all the things! — SOURCE

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.

First steps with vectorized functions

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.

For loop version:

a = [1,2,3];

	for i in 1:length(a)
	    a[i] += 1
	end
julia> print(a)

[2, 3, 4]

Vectorized version:

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.

	a = [1,2,3];

	a .+ 1

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:

This gives the same answer as the for loop above. And there’s no need to convert your array.

SOURCE

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:

function area_of_circle(r)
	    return π * r^2
	end

	a = [1,2,3];
	area_of_circle.(a)

Yes, pi is a built in constant in Julia!

julia> area_of_circle.(a)

3-element Array{Float64,1}:
  3.141592653589793
 12.566370614359172
 28.274333882308138

Bye-bye for loops

Image for post

Bye-bye for loops! — SOURCE

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:

	function fizzbuzz(n)
	    return collect(1:n)
	end

Here, collect just takes our range operator and evaluates it to an array.

julia> fizzbuzz(5)

5-element Array{Int64,1}:
 1
 2
 3
 4
 5

Adding Fizzes

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 Buzzes

Adding the Buzzes is done exactly the same way:

#programming #julia #optimization #coding #vectorization

Vectorize everything with Julia
1.70 GEEK