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;
}
|