TL;DR

Here we are with TASK #1 from The Weekly Challenge #162. Enjoy!

# The challenge

Write a script to generate the check digit of given ISBN-13 code. Please refer wikipedia for more information.

Example

ISBN-13 check digit for '978-0-306-40615-7' is 7.


# The questions

I’m assuming that no validation of the inputs have to be done, like making sure that there are 12+1 digits, separators are in the right place, etc.

# The solution

Let’s first reshuffle the formula for calculating the goal value:

$x_{13} = (10 - ((x_1 + 3 x_2 + x_3 + 3 x_4 + ... + x_{11} + 3 x_{12}) \mod{10})) \mod{10} \\ x_{13} = (- (x_1 + 3 x_2 + x_3 + 3 x_4 + ... + x_{11} + 3 x_{12})) \mod{10} \\ x_{13} = (-x_1 - 3 x_2 - x_3 - 3 x_4 + ... - x_{11} - 3 x_{12}) \mod{10} \\ x_{13} = \sum_{i = 1}^{6} (-x_{2i-1} - 3 x_{2i}) \mod{10}$

So we can take pairs of consecutive digits and address them as in the parenthesis in the summation above.

Let’s start Raku:

#!/usr/bin/env raku
use v6;
sub MAIN (Str:D $input = '978-0-306-40615-7') { put "ISBN-13 check digit for '$input' is {isbn_13($input)}."; } sub isbn_13 ($input) {
$input.comb(/\d/)[0..11] # focus on first 12 digits .map({-$^a - 3 * $^b}) # apply equivalent weights .sum % 10; # sum and take remainder }  We’re concentrating on the first 12 digits, so the comb gets the digits and the slice [0..11] takes the first 12 of them. The following map/sum tandem implements the formula seen above. Let’s go Perl now, trying to show some Raku-ish dialect! #!/usr/bin/env perl use v5.24; use warnings; use experimental 'signatures'; no warnings 'experimental::signatures'; use List::Util qw< pairmap sum >; my$input = shift // '978-0-306-40615-7';
say "ISBN-13 check digit for '$input' is @{[isbn_13($input)]}.";

sub isbn_13 ($input) { sum( pairmap { -$a - 3* $b } ($input =~ m{(\d)}gmxs)[0 .. 11]
) % 10;
}


Function pairmap only appeared in version 1.29 of List::Util, but we are OK with the constraint on perl’s version which appeared three years later (give or take a couple of months). It allows us to replicate the map taking two values at a time behaviour that comes stock in Raku, so why not?

The other rakuism is in the embedding of the call to isbn_13 directly into the string:

say "ISBN-13 check digit for '$input' is @{[isbn_13($input)]}.";
#                                        ^^^^^^^^^^^^^^^^^^^^


This is hackish in Perl, although it also funnily gets an aura of secret operator (apparently, it’s the Babycart operator).

Stay safe!