Skip to content

Commit f776090

Browse files
committed
Add anagram to generator
1 parent 4ad8751 commit f776090

File tree

5 files changed

+248
-104
lines changed

5 files changed

+248
-104
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
exercise: Anagram
2+
plan: 15
3+
subs: match_anagrams
4+
tests: |-
5+
for my $case (@test_cases) {
6+
is match_anagrams($case->{input}), $case->{expected}, $case->{description};
7+
}
8+
9+
example: |-
10+
sub match_anagrams {
11+
my ($input) = @_;
12+
return [];
13+
}
14+
15+
stub: |-
16+
sub match_anagrams {
17+
my ($input) = @_;
18+
return undef;
19+
}
Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,12 @@
11
package Anagram;
22
use strict;
33
use warnings;
4+
use Exporter 'import';
5+
our @EXPORT_OK = qw(match_anagrams);
46

5-
sub match {
6-
my ( $word, @words ) = @_;
7-
8-
my @results;
9-
my $canonical = _canonize($word);
10-
foreach my $w (@words) {
11-
next if $w eq $word;
12-
my $try = _canonize($w);
13-
if ( $try eq $canonical ) {
14-
push @results, $w;
15-
}
16-
}
17-
return \@results;
18-
}
19-
20-
sub _canonize {
21-
my ($str) = @_;
22-
return join '', sort split //, lc $str;
7+
sub match_anagrams {
8+
my ($input) = @_;
9+
return [];
2310
}
2411

2512
1;

exercises/anagram/Anagram.pm

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package Anagram;
2+
use strict;
3+
use warnings;
4+
use Exporter 'import';
5+
our @EXPORT_OK = qw(match_anagrams);
6+
7+
sub match_anagrams {
8+
my ($input) = @_;
9+
return undef;
10+
}
11+
12+
1;

exercises/anagram/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Anagram
22

3-
Given a word and a list of possible anagrams, select the correct sublist.
3+
An anagram is a rearrangement of letters to form a new word.
4+
Given a word and a list of candidates, select the sublist of anagrams of the given word.
45

56
Given `"listen"` and a list of candidates like `"enlists" "google"
67
"inlets" "banana"` the program should return a list containing

exercises/anagram/anagram.t

Lines changed: 210 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,98 +1,223 @@
11
#!/usr/bin/env perl
2-
use strict;
3-
use warnings;
2+
use Test2::V0;
3+
use JSON::PP;
4+
use constant JSON => JSON::PP->new;
45

5-
use Test2::Bundle::More;
6-
use JSON::PP qw(decode_json);
76
use FindBin qw($Bin);
87
use lib $Bin, "$Bin/local/lib/perl5";
98

10-
my $module = 'Anagram';
9+
use Anagram qw(match_anagrams);
1110

12-
my $cases;
13-
{
14-
local $/ = undef;
15-
$cases = decode_json scalar <DATA>;
16-
}
17-
18-
plan 3 + @$cases;
19-
20-
#diag explain $cases;
21-
22-
ok -e "$Bin/$module.pm", "missing $module.pm"
23-
or BAIL_OUT(
24-
"You need to create a class called $module.pm with an function called match() that gets the original word as the first parameter and a reference to a list of word to check. It should return a referene to a list of words."
25-
);
11+
my @test_cases = do { local $/; @{ JSON->decode(<DATA>) }; };
12+
plan 15;
2613

27-
eval "use $module";
28-
ok !$@, "Cannot load $module.pm"
29-
or BAIL_OUT("Does $module.pm compile? Does it end with 1; ?");
14+
imported_ok qw(match_anagrams) or bail_out;
3015

31-
can_ok( $module, 'match' )
32-
or BAIL_OUT("Missing package $module; or missing sub match()");
33-
34-
my $sub = $module . '::match';
35-
36-
foreach my $c (@$cases) {
37-
no strict 'refs';
38-
is_deeply $sub->( $c->{word}, @{ $c->{words} } ), $c->{expected},
39-
$c->{name};
16+
for my $case (@test_cases) {
17+
is match_anagrams( $case->{input} ), $case->{expected},
18+
$case->{description};
4019
}
4120

4221
__DATA__
4322
[
44-
{
45-
"word" : "diaper",
46-
"words" : ["hello", "world", "zombies", "pants"],
47-
"expected" : [],
48-
"name" : "no matches"
49-
},
50-
{
51-
"word" : "ant",
52-
"words" : ["tan", "stand", "at"],
53-
"expected" : ["tan"],
54-
"name" : "detect_simple_anagram"
55-
},
56-
{
57-
"word" : "master",
58-
"words" : ["stream", "pigeon", "maters"],
59-
"expected" : ["stream", "maters"],
60-
"name" : "multiple_anagrams"
61-
},
62-
{
63-
"word" : "galea",
64-
"words" : ["eagle"],
65-
"expected" : [],
66-
"name" : "does_not_confuse_different_duplicates"
67-
},
68-
{
69-
"word" : "good",
70-
"words" : ["dog", "goody"],
71-
"expected" : [],
72-
"name" : "eliminate_anagram_subsets"
73-
},
74-
{
75-
"word" : "listen",
76-
"words" : ["enlists", "google", "inlets", "banana"],
77-
"expected" : ["inlets"],
78-
"name" : "detect_anagram"
79-
},
80-
{
81-
"word" : "allergy",
82-
"words" : ["gallery", "ballerina", "regally", "clergy", "largely", "leading"],
83-
"expected" : ["gallery", "regally", "largely"],
84-
"name" : "multiple_anagrams"
85-
},
86-
{
87-
"word" : "Orchestra",
88-
"words" : ["cashregister", "Carthorse", "radishes"],
89-
"expected" : ["Carthorse"],
90-
"name" : "anagrams_are_case_insensitive"
91-
},
92-
{
93-
"word" : "banana",
94-
"words" : ["banana"],
95-
"expected" : [],
96-
"name" : "same_word_isnt_anagram"
97-
}
23+
{
24+
"description" : "no matches",
25+
"expected" : [],
26+
"input" : {
27+
"candidates" : [
28+
"hello",
29+
"world",
30+
"zombies",
31+
"pants"
32+
],
33+
"subject" : "diaper"
34+
},
35+
"property" : "findAnagrams"
36+
},
37+
{
38+
"description" : "detects two anagrams",
39+
"expected" : [
40+
"stream",
41+
"maters"
42+
],
43+
"input" : {
44+
"candidates" : [
45+
"stream",
46+
"pigeon",
47+
"maters"
48+
],
49+
"subject" : "master"
50+
},
51+
"property" : "findAnagrams"
52+
},
53+
{
54+
"description" : "does not detect anagram subsets",
55+
"expected" : [],
56+
"input" : {
57+
"candidates" : [
58+
"dog",
59+
"goody"
60+
],
61+
"subject" : "good"
62+
},
63+
"property" : "findAnagrams"
64+
},
65+
{
66+
"description" : "detects anagram",
67+
"expected" : [
68+
"inlets"
69+
],
70+
"input" : {
71+
"candidates" : [
72+
"enlists",
73+
"google",
74+
"inlets",
75+
"banana"
76+
],
77+
"subject" : "listen"
78+
},
79+
"property" : "findAnagrams"
80+
},
81+
{
82+
"description" : "detects three anagrams",
83+
"expected" : [
84+
"gallery",
85+
"regally",
86+
"largely"
87+
],
88+
"input" : {
89+
"candidates" : [
90+
"gallery",
91+
"ballerina",
92+
"regally",
93+
"clergy",
94+
"largely",
95+
"leading"
96+
],
97+
"subject" : "allergy"
98+
},
99+
"property" : "findAnagrams"
100+
},
101+
{
102+
"description" : "detects multiple anagrams with different case",
103+
"expected" : [
104+
"Eons",
105+
"ONES"
106+
],
107+
"input" : {
108+
"candidates" : [
109+
"Eons",
110+
"ONES"
111+
],
112+
"subject" : "nose"
113+
},
114+
"property" : "findAnagrams"
115+
},
116+
{
117+
"description" : "does not detect non-anagrams with identical checksum",
118+
"expected" : [],
119+
"input" : {
120+
"candidates" : [
121+
"last"
122+
],
123+
"subject" : "mass"
124+
},
125+
"property" : "findAnagrams"
126+
},
127+
{
128+
"description" : "detects anagrams case-insensitively",
129+
"expected" : [
130+
"Carthorse"
131+
],
132+
"input" : {
133+
"candidates" : [
134+
"cashregister",
135+
"Carthorse",
136+
"radishes"
137+
],
138+
"subject" : "Orchestra"
139+
},
140+
"property" : "findAnagrams"
141+
},
142+
{
143+
"description" : "detects anagrams using case-insensitive subject",
144+
"expected" : [
145+
"carthorse"
146+
],
147+
"input" : {
148+
"candidates" : [
149+
"cashregister",
150+
"carthorse",
151+
"radishes"
152+
],
153+
"subject" : "Orchestra"
154+
},
155+
"property" : "findAnagrams"
156+
},
157+
{
158+
"description" : "detects anagrams using case-insensitive possible matches",
159+
"expected" : [
160+
"Carthorse"
161+
],
162+
"input" : {
163+
"candidates" : [
164+
"cashregister",
165+
"Carthorse",
166+
"radishes"
167+
],
168+
"subject" : "orchestra"
169+
},
170+
"property" : "findAnagrams"
171+
},
172+
{
173+
"description" : "does not detect an anagram if the original word is repeated",
174+
"expected" : [],
175+
"input" : {
176+
"candidates" : [
177+
"go Go GO"
178+
],
179+
"subject" : "go"
180+
},
181+
"property" : "findAnagrams"
182+
},
183+
{
184+
"description" : "anagrams must use all letters exactly once",
185+
"expected" : [],
186+
"input" : {
187+
"candidates" : [
188+
"patter"
189+
],
190+
"subject" : "tapper"
191+
},
192+
"property" : "findAnagrams"
193+
},
194+
{
195+
"description" : "words are not anagrams of themselves (case-insensitive)",
196+
"expected" : [],
197+
"input" : {
198+
"candidates" : [
199+
"BANANA",
200+
"Banana",
201+
"banana"
202+
],
203+
"subject" : "BANANA"
204+
},
205+
"property" : "findAnagrams"
206+
},
207+
{
208+
"description" : "words other than themselves can be anagrams",
209+
"expected" : [
210+
"Silent"
211+
],
212+
"input" : {
213+
"candidates" : [
214+
"Listen",
215+
"Silent",
216+
"LISTEN"
217+
],
218+
"subject" : "LISTEN"
219+
},
220+
"property" : "findAnagrams"
221+
}
98222
]
223+

0 commit comments

Comments
 (0)