🎄 6/25. Testing palindromic numbers in Perl 6

🎄 6/25. Testing palindromic numbers in Raku

N. B. Perl 6 has been renamed to Raku. Click to read more.


Welcome to Day 6 of the Perl 6 One-Liner Advent Calendar! As promised yesterday, today we’ll be solving problem 4 of Project Euler. Let me once again remind you that you can pause reading and solve the problem yourself first. My intention is to demonstrate the beauty of Perl 6 and Perl in general.

So, the task is to find the largest palindromic number (the number that reads from both ends, such as 1551), which is a product of two three-digit numbers.

In other words, we have to scan the numbers below 999×999, and could optimise the solution, but in reality, we only have to allow numbers, which are products, thus, let’s not skip the multiplication part.

Here’s our today’s one-liner:

(((999...100) X* (999...100)).grep: {$^a eq $^a.flip}).max.say

If you are reading this advent calendar, then you are already prepared to the fact that chained method calls are very handy for using in Perl 6 one-liners.

We also saw the colon-form of grep earlier in Day 2, but this time we are using a code block with a placeholder variable. It is not quite clear if you can use a star here, as we need the variable twice in the block.

The first part of the line uses the cross operator X*, we’ll return to it in a few days here in this series. It generates products of all three-digit numbers. As we need the largest number, it makes sense to start from right to left, that’s why the sequence 999...100, but not 100...999.

Let’s look at the first few numbers in the grepped sequence of products:

580085 514415 906609 119911 282282 141141 853358 650056

One-liners are not always very optimal. In our case, we need to generate the whole sequence of products to find the maximum among them. The answer resides at the third position, so it will be a mistake to replace max with first. But the good part is that if you use first, Perl 6 will not generate all the numbers. There’s another useful method, head, which also prevents generating more than necessary.

The following code runs much faster and gives the correct result:

(((999...100) X* (999...100)).grep:
{$^a eq $^a.flip}).head(10).max.say

And let’s stop here for today. Stay tuned!

2 thoughts on “🎄 6/25. Testing palindromic numbers in Perl 6”

  1. sub is-palindrome (Int $a)
    {
        return $a.Str eq $a.Str.flip;
    }
    
    my %res = a => 0, b => 0, num => 0;
    
    loop (my $a = 999; $a > 99; $a--) {
        loop (my $b = 999; $b > 99; $b--) {
            last if $a < %res<a> && $b < %res<b>;
    
            my $n = $a * $b;
            if is-palindrome($n) && %res  $a, b => $b, num => $n;
            }
        }
    }
    
    say %res;
    

    my solution

Leave a Reply

Your email address will not be published. Required fields are marked *

Retype the CAPTCHA code from the image
Change the CAPTCHA codeSpeak the CAPTCHA code