aboutsummaryrefslogtreecommitdiff
path: root/challenge-094/jo-37/perl/ch-1.pl
blob: 0e8dc4860be0ca086226cd067b88b884ea0c7eb2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#!/usr/bin/perl -s

use v5.16;
use Test2::V0;
use experimental 'postderef';

our $examples;

run_examples() if $examples; # does not return

say(<<EOS), exit unless @ARGV;
Usage: $0 [-examples] [word ...]

-examples
    runs the given examples

word ... 
    use given words as input
EOS

# Apply "anagroup" to @ARGV and convert the result into the requested
# format.
say '[ ' .
    (join ', ', map {
        '(' . (join ', ', map {qq{"$_"}} @$_) . ')'
        } anagroup(@ARGV)) .
    ' ]';

# Group given strings by anagrams.
sub anagroup {
    # Hash to collect anagrams by a canonical key.
    my %anagroup;

    # Split strings into characters, sort and rejoin to gain a
    # "canonical anagram", decorate each string with its canonical
    # anagram and collect the strings within the prepared hash by
    # canonical key.
    push $anagroup{$_->[0]}->@*, $_->[1]
        foreach map {[join('', sort split //), $_]} @_;

    # Sort the canonical anagrams and retrieve the corresponding string
    # lists.  (The sort is required for a stable result only.)
    map {$anagroup{$_}} sort keys %anagroup;
}

sub run_examples {
    is [anagroup qw(opt bat saw tab pot top was)],
        [[qw(bat tab)], [qw(saw was)], [qw(opt pot top)]], 'Example 1';
    is [anagroup 'x'], [['x']], 'Example 2';

    done_testing;
    exit;
}