🎄 11/25. Solving the Problem 34 in Perl 6

🎄 11/25. Solving the Problem 34 in Raku

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


Welcome to Day 11 of the Perl 6 One-Liner Advent Calendar! Today, the calendar post is totally devoted to the solution of problem 34 of Project Euler. Once again, let me warn you to pause reading if you want to find your own solution prior to seeing mine.

So, the task is to find the sum of all numbers, which are equal to the sum of factorials of their digits. Sounds clear? 🙂 You may take a look at the solution one-liner to understand it better.

say [+] (3..50_000).grep({$_ == [+] .comb.map({[*] 2..$_})})

Let us start from … something.

We are looping over a range 3 .. 50_000. The upper boundary is a guess based on some considerations. I would not be explaining it here, but you may try to find the answer if you are curious. Basically, at some point you understand that the number either contains too many digits or is too big itself. Refer to the discussion on Project Euler to get a pure explanation.

The second step is to grep. We are searching for numbers, which are equal ($_ ==) to the sum. It is calculated by the second reduction plus [+], but you may use the sum method instead:

{$_ == .comb.map({[*] 2..$_}).sum}

Notice that .comb is a method called on the default variable $_. The comb method splits the number to separate digits (as characters). The map method converts each digit to a factorial (again, using the reduction operator [*], as we did it yesterday).

Finally, the most outer [+] adds up all the grepped numbers, and passes the result to the say routine.

Although the main idea was to show a one-liner, in real practice it would be wiser to prepare the factorials before using them:

my @f = (0..9).map({[*] 1..$_});
say [+] (3..50_000).grep({$_ == [+] .comb.map({@f[$_]})});

And that’s the end of today’s story. There are more for the rest of this calendar!