Challenge 1

Let’s start with the simplest scenario: one-word anagrams. Let’s say you have a word — wolf — and want to find its anagrams (it has only one, “flow”). A good starting point is to split the word into its parts, the characters, so that you can manipulate it to find the anagram. For the splitting you can use the routine .comb on the string. That returns a List with the characters.

Now — the List object has an interesting routine, .permutations. You won’t find an equivalent to this in Perl 5 without resorting to modules. This great function is just built-in to Perl 6, so let’s use it: A naive way of trying to find anagrams would be to apply permutations on the list.

> "wolf".comb.permutations

((f l o w) (f l w o) (f o l w) (f o w l) (f w l o) (f w o l) (l f o w) (l f w o) (l o f w) (l o w f) (l w f o) (l w o f) (o f l w) (o f w l) (o l f w) (o l w f) (o w f l) (o w l f) (w f l o) (w f o l) (w l f o) (w l o f) (w o f l) (w o l f))

And sure enough, “flow” is the first result! However, permutations are just that: Permutations. There is no guarantee that the permutation in question actually is a word. So we have to introduce a dictionary to check the permutations against.

On my Mac (macos 10.14.1), there’s a dictionary of a couple of hundred thousand words in the file /usr/share/dict/words . Many Linux distributions has the same, and for those distributions and operating systems which don’t, dictionaries are easy to find on line. In this example I assume the existence of that dictionary file.

What the code below does: Line 1 reads the dictionary and stores it in memory. I convert it to a hash where each word has the value True . This makes it easy to check a word’s existence: Just try to access the element in the %dict variable. If the returned value is True , then we’re OK.

Line 2 tries to figure out whether you provide words to the script through stdin (using a pipe) or as arguments on the command line. It then loops through the words provided and tries to find anagrams that matches (lines 3 and 4).

File: anagrams.p6 my %dict = "/usr/share/dict/words".IO.lines().map({ $_.lc => True});

for @*ARGS ?? @*ARGS !! ! $*IN.t ?? lines() !! Nil -> $w {

say "$w - $_" if %dict{$_} and $_ ne $w

for unique do for $w.lc.comb.permutations { $_.join };

}

There you have it: The solution to Challenge 1 is four lines of code (in reality three lines, because I added a newline for readability’s sake).

# Output: $ perl6 anagrams.p6 fowl tornado

fowl - flow

fowl - wolf

tornado - odorant

tornado - donator

A couple of noteworthy things here: For some reason .permutations doesn’t guarantee that a permutation is unique. The returned list can therefore contain duplicates. So I use unique to filter out duplicates.

Note $*IN.t ; the special variable $*IN is Perl 6’s name for STDIN . It has a few methods and properties among them the method .t . That returns True or False depending on whether the program can expect standard input to come from the terminal (tty) or through a pipe.

Note: If you prefer, you could rewrite line 3 so that no if’s or for’s are used at all. It would look something like this:

my $dict = "/usr/share/dict/words".IO.lines()>>.lc.Set;

for @*ARGS ?? @*ARGS !! ! $*IN.t ?? lines() !! '' -> $w {

$w.lc.comb.permutations>>.join.grep({ $dict{$_} and $_ ne $w }).map({ "$w\t$_

" }).unique.join.say;

}

As you can see I’ve used >> (.hyper) here. That thing tries to run the .join in batches in parallell, and therefore potentially much faster. There’s no notable speed difference here, but I thought I’d start implementing it anyway so that it’s there when it can have effect.