<?php
define('WORD_LIST_FILENAME', '/usr/share/dict/words');
class AnagramLookup
{
private $lookup;
// Loads a file with one word per line
private function load_word_list($filename)
{
$lines = file($filename); // One word per line
$lines = array_map('trim', $lines); // Strip any excess whitespace
$lines = array_filter($lines, 'ctype_alpha'); // Words been to match [a-zA-Z]
$lines = array_map('strtolower', $lines); // Set all the words to lowercase
$lines = array_unique($lines); // Remove any duplicate words
$lines = array_diff($lines, array('')); // Remove any empty lines
return $lines;
}
// Sort the individual letters in a string
// i.e. tale => aelt
private function sort_letters($word)
{
$letters = str_split($word);
sort($letters);
$sorted_word = implode('', $letters);
return $sorted_word;
}
// Generate our lookup table. This takes ~1.5second for 70,000 words
// $lookup ends up looking like:
//
// $lookup[4] = array
// (
// 'aelt' => array('late', 'tale', 'leta', 'teal'),
// 'belu' => array('blue', 'lube'),
// [etc...]
// )
// $lookup[5] = array
// (
// 'allms' => array('small', 'malls'),
// [etc...]
// )
//
// 4 and 5 are the word lengths, while 'aelt', 'belu' and 'allms' contains
// an array of all the words that can be spelt using these letters
public function __construct($filename)
{
$word_list = $this->load_word_list($filename);
$lookup = array();
foreach($word_list as $word)
{
$length = strlen($word);
if(!isset($lookup[$length]))
{
$lookup[$length] = array();
}
$sorted_word = $this->sort_letters($word);
if(!isset($lookup[$length][$sorted_word]))
{
$lookup[$length][$sorted_word] = array();
}
$lookup[$length][$sorted_word][] = $word;
}
$this->lookup = $lookup;
}
// Return all the anagrams of the passed word
public function lookup_word($word)
{
$word_length = strlen($word);
$sorted_word = $this->sort_letters($word);
if(isset($this->lookup[$word_length][$sorted_word]))
{
return $this->lookup[$word_length][$sorted_word];
}
return array();
}
// Return an array of all the sets of anagrams with a specific length
//
// Example result for a word length of 14:
//
// array
// (
// [0] => array('certifications','rectifications'),
// [1] => array('impressiveness','permissiveness'),
// [2] => array('tablespoonfuls','tablespoonsful'),
// )
public function all_of_length($word_length)
{
if(!isset($this->lookup[$word_length]))
{
return array();
}
$results = array();
foreach($this->lookup[$word_length] as $words)
{
if(count($words) > 1)
{
$results[] = $words;
}
}
return $results;
}
}
$anagram = new AnagramLookup(WORD_LIST_FILENAME);
printf("Anagrams of 'blue': %s\n", implode(', ', $anagram->lookup_word('blue')));
printf("Anagrams of 'late': %s\n", implode(', ', $anagram->lookup_word('late')));
printf("Anagrams of 'slow': %s\n", implode(', ', $anagram->lookup_word('slow')));
printf("Anagrams of 'seven': %s\n", implode(', ', $anagram->lookup_word('seven')));
printf("Anagrams of 'anagram': %s\n", implode(', ', $anagram->lookup_word('anagram')));
printf("All anagrams of word length 14\n");
foreach($anagram->all_of_length(7) as $words)
{
printf(" * %s\n", implode(', ', $words));
}
?>