๐ŸŽ„ 2/25. Grepping dividable numbers in Perl 6

Welcome to Day 2 of the Perl 6ย One-Liner Advent Calendar! Today, weโ€™ll solve a nice task from Project Euler with number 1. Once again, let me warn you that the rest of the text contains a solution, so you are welcome to make a pause to think of your own solution first. But I am almost sure that if you are reading perl6.online then you most likely solved the problems from Project Euler in the past.

The task is to find the sum of all multiples of 3 and 5 below 1000. The first elements of the row of our interest are 3, 5, 9, 15, 20, 21, etc. You can already see that some of them, such as 15, are multiples of both 3 and 5, so it is not possible to add up multiples of 3 and 5 separately.

The short story is here:

say sum((1..999).grep: * %% (3 | 5))

Now let us decipher it.

What we need is to filter the numbers that are multiples of either 3 or 5. If you re-read the previous sentence, a bell should ring for you: in Perl 6 this can be achieved with junctions, informally known as quantum superpositions. To test if a number is dividable by either 3 or 5, write the following:

$x %% 3 | 5

By the way, %%, the divisibility operator, is a very sweet thing that helps avoiding negations in Boolean tests, which you would have written as follows, would you only have a single percent:

!($x % (3 | 5))

OK, the main condition is ready, let us scan the numbers between 1 and (including) 999:

(1..999).grep: * %% (3 | 5)

A few more interesting Perl 6 elements appear here. For example, the WhateverCodeย block, which was introduced by a * character (learn more about it in my article All the stars of Perl 6 published in the previous Perl 6 Advent Calendar). Together with the colon-form of method calls, it allows to get rid of a nested pair of braces and parentheses:

(1..999).grep({$_ %% (3 | 5)})

The numbers are filtered (grepped if you prefer), and itโ€™s time to add them up and print the result. We come to the final one-liner shown at the beginning of this post.

Of course, instead of writing say sum(...)ย one could do a method call or two:

((1..999).grep: * %% (3 | 5)).sum.say

As a bonus track, hereโ€™s my first solution:

sub f($n) {
    ($n <<*>> (1...1000 / $n)).grep: * < 1000

say (f(3) โˆช f(5)).keys.sum;

And thatโ€™s the end of todayโ€™s story! Come again tomorrow!

3 thoughts on “๐ŸŽ„ 2/25. Grepping dividable numbers in Perl 6”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s