extract word matching
This commit is contained in:
parent
bc99731e62
commit
47141cf4c0
5 changed files with 114 additions and 39 deletions
|
|
@ -2,43 +2,25 @@
|
|||
|
||||
require __DIR__ . '/../autoload.php';
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\LazyCollection;
|
||||
use Myrmidex\AnagramFinder\ArgHandler;
|
||||
use Myrmidex\AnagramFinder\Matcher;
|
||||
use Myrmidex\AnagramFinder\Output;
|
||||
|
||||
const DICTIONARY = __DIR__ . '/../assets/words.txt';
|
||||
|
||||
echo "ANAGRAM FINDER\n";
|
||||
Output::line("ANAGRAM FINDER");
|
||||
|
||||
$words = LazyCollection::make(function () {
|
||||
$fh = fopen(DICTIONARY, 'rb');
|
||||
try {
|
||||
while (($line = fgets($fh)) !== false) {
|
||||
yield rtrim($line, "\r\n");
|
||||
}
|
||||
} finally {
|
||||
fclose($fh);
|
||||
}
|
||||
});
|
||||
$args = ArgHandler::make($argv);
|
||||
$anagram = $args->get(1) ?: readline("Enter the anagram: ");
|
||||
$minLength = $args->get(2) ?: 3;
|
||||
$top10 = $args->hasOption('top');
|
||||
|
||||
function output($message)
|
||||
{
|
||||
$message = $message . PHP_EOL;
|
||||
print($message);
|
||||
flush();
|
||||
// ob_flush();
|
||||
Output::line();
|
||||
Output::line("Results for your anagram: " . $anagram);
|
||||
|
||||
$matches = Matcher::findWords($anagram, $minLength);
|
||||
if ($top10) {
|
||||
$matches = $matches->slice(0, 10);
|
||||
}
|
||||
$matches->each(fn (string $word) => Output::line($word . " (" . strlen($word) . ")"));
|
||||
|
||||
|
||||
$anagramBase = readline("Enter the anagram: ");
|
||||
echo "\n";
|
||||
echo "Results for your anagram: " . $anagramBase . "\n";
|
||||
|
||||
$anagramChars = new Collection(explode($anagramBase, ""));
|
||||
echo $words
|
||||
->filter(fn (string $word) => ctype_alpha($word))
|
||||
->filter(fn (string $word) => strtolower($word) === $word)
|
||||
->map(fn (string $word) => new Collection(explode($word, "")))
|
||||
->filter(fn (Collection $wordChars) => $wordChars->count() === $anagramChars->intersect($wordChars)->count())
|
||||
->count();
|
||||
// ->map(fn (Collection $wordChars) => $wordChars->join(""))
|
||||
// ->each(fn (string $word) => output($word));
|
||||
|
|
|
|||
33
src/ArgHandler.php
Normal file
33
src/ArgHandler.php
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
namespace Myrmidex\AnagramFinder;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class ArgHandler
|
||||
{
|
||||
private Collection $args;
|
||||
|
||||
public function __construct(array $argv)
|
||||
{
|
||||
$this->args = new Collection($argv);
|
||||
}
|
||||
|
||||
public static function make(array $argv): self
|
||||
{
|
||||
return new self($argv);
|
||||
}
|
||||
|
||||
public function get(int $index)
|
||||
{
|
||||
return $this->args
|
||||
->reject(fn ($word) => substr($word, 0, 2) === '--')
|
||||
->get($index);
|
||||
}
|
||||
|
||||
public function hasOption(string $option) {
|
||||
return $this->args
|
||||
->filter(fn ($word) => $word === '--' . $option)
|
||||
->isNotEmpty();
|
||||
}
|
||||
}
|
||||
|
|
@ -3,15 +3,49 @@
|
|||
namespace Myrmidex\AnagramFinder;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\LazyCollection;
|
||||
|
||||
class Matcher
|
||||
{
|
||||
public static function findWords(string $anagram, int $minLength = 3): Collection
|
||||
{
|
||||
$matches = self::getWordList()
|
||||
->filter(fn (string $word) => strlen($word) >= $minLength)
|
||||
->filter(fn (string $word) => ctype_alpha($word))
|
||||
->filter(fn (string $word) => $word === strtolower($word))
|
||||
->filter(fn (string $word) => self::check($anagram, $word))
|
||||
->toArray();
|
||||
|
||||
return new Collection($matches)
|
||||
->sort(fn ($a, $b) => strlen($b) - strlen($a));
|
||||
}
|
||||
|
||||
public static function check(string $anagram, string $word): bool
|
||||
{
|
||||
$available = (new Collection(str_split($anagram)))->countBy();
|
||||
$pool = array_count_values(str_split($anagram));
|
||||
|
||||
return (new Collection(str_split($word)))
|
||||
->countBy()
|
||||
->every(fn (int $needed, string $letter) => $available->get($letter, 0) >= $needed);
|
||||
foreach (str_split($word) as $char) {
|
||||
if (($pool[$char] ?? 0) === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$pool[$char]--;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static function getWordList(): LazyCollection
|
||||
{
|
||||
return LazyCollection::make(function () {
|
||||
$fh = fopen(DICTIONARY, 'rb');
|
||||
try {
|
||||
while (($line = fgets($fh)) !== false) {
|
||||
yield rtrim($line, "\r\n");
|
||||
}
|
||||
} finally {
|
||||
fclose($fh);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
12
src/Output.php
Normal file
12
src/Output.php
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
|
||||
namespace Myrmidex\AnagramFinder;
|
||||
|
||||
class Output
|
||||
{
|
||||
public static function line(string $message = ''): void
|
||||
{
|
||||
print($message . PHP_EOL);
|
||||
flush();
|
||||
}
|
||||
}
|
||||
|
|
@ -2,12 +2,26 @@
|
|||
|
||||
namespace Myrmidex\AnagramFinder\Tests\Unit;
|
||||
|
||||
use Myrmidex\AnagramFinder\Matcher;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
final class MatcherTest extends TestCase
|
||||
{
|
||||
public function testCheck()
|
||||
#[DataProvider('checkProvider')]
|
||||
public function testCheck(string $anagram, string $word, bool $isExpectedMatch)
|
||||
{
|
||||
return;
|
||||
$this->assertEquals($isExpectedMatch, Matcher::check($anagram, $word));
|
||||
}
|
||||
|
||||
public static function checkProvider(): array
|
||||
{
|
||||
return [
|
||||
'valid1' => [ "eamstoxil", "steam", true ],
|
||||
'valid2' => [ "wordneoxs", "downers", true ],
|
||||
'valid3' => [ "ioevpmoef", "movie", true ],
|
||||
'invalid_basic' => [ "eamstoxil", "smear", false],
|
||||
'invalid_double_e' => [ "eamstexil", "smear", false],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue