Stones and Jewels

This is a solution to task #1 from the 26th Perl Weekly Challenge, written in Perl 6.

Create a script that accepts two strings, let us call it, “stones” and “jewels”. It should print the count of “alphabet” from the string “stones” found in the string “jewels”. For example, if your stones is “chancellor” and “jewels” is “chocolate”, then the script should print “8”. To keep it simple, only A-Z,a-z characters are acceptable. Also make the comparison case sensitive.

The problem can be solved with a one-liner:

[+] 'chancellor'.comb(/<[A..Z a..z]>/).Bag{'chocolate'.comb(/<[A..Z a..z]>/).Bag.keys}

Let's break that up a bit and describe the details:

[+]                            # reduce to the sum of values
    .comb(/<[A..Z a..z]>/)     # Literally 'comb' out the characters
                               #  of interest from stones
    .Bag                       # Create a bag counting the characters
                               #   Bag(a, c(2), e, h, l(2), n, o, r)
   {                           # Take a slice of the stones bag
       .comb(/<[A..Z a..z]>/)  # characters of jewels
       .Bag                    # into a bag
       .keys                   # giving a set of unique characters
                               #   (o a t l e h c)
   }                           # Slice returns the count of stone characters
                               #   for each jewel character (2 0 1 1 1 2 1)

To complete the task, we need to turn the one-liner into a usable script. There's an opportunity to eliminate some duplication at the same time.

#!/usr/bin/env perl6

sub MAIN(Str $stones, Str $jewels) {

    sub collect(Str $s) { $s.comb(/<[A..Z a..z]>/).Bag }

    say [+] collect($stones){collect($jewels).keys};
./stones-and-jewels.p6 chancellor chocolate
./stones-and-jewels.p6 'Chancellor Bing' 'chocolate boy'
comments powered by Disqus