tags:

views:

121

answers:

2

Hi,

i search a method to compare scrambled words with a wordlist full of unscrambled words for example:

the scrambled word is "lonbayb" and somewhere in the wordlist is the word "babylon". the script should show me the unscrambled word

any idea how to solve this problem?

+5  A: 

A simple solution that comes to mind is to sort the letters in both the scrambled and unscrambled words, alphabetically, before comparing. I'll call this "shuffling":

"babylon" ==> "abblnoy"

In practical terms, you should create a second wordlist from your reference wordlist, with the reference wordlist having its entries shuffled like this.

and then when you're looking at a new word and want to know if it's in the list, shuffle that the same way and you can do a simple search in your shuffled reference list. If you sort words in the shuffled reference list alphabetically, you can even do a binary search on it. Or you put the shuffled reference words into a hashset or a b-tree... whatever is easy to quickly search in.

Carl Smotricz
Yeah, you could build a database table with the sorted and unsorted versions of each word. When you want to check a word, just sort it's chars and put it into a WHERE clause in your SQL. You'd even get multiple results automatically if there are any.
Techpriester
Sure, but only for huge word lists in excess of several megabytes. For anything less, I'd use in-memory data structures, with far superior performance and less DB-related busywork.
Carl Smotricz
A: 

To shuffle the words use str_shuffle(). To compare a shuffled string to a wordlist, you can use count_chars().

class WordFinder
{
    protected $_wordList;
    protected $_map;

    public function __construct(array $wordList)
    {
        $this->_wordList = $wordList;
    }

    protected function _initMap()
    {
        if(!is_array($this->_map)) {
            $this->_map = array();
            foreach($this->_wordList as $word) {
                $key = count_chars($word, 3);
                if(!isset($this->_map[$key])) {
                    $this->_map[$key] = array();
                }
                $this->_map[$key][] = $word;
            }
        }
    }

    public function findWords($searchWord)
    {
        $searchWord = count_chars($searchWord, 3);
        $this->_initMap();
        if(isset($this->_map[$searchWord])) {
            return $this->_map[$searchWord];
        }
        return false;
    }    
}

Then do

$list   = array('evil', 'live', 'vile', 'cat');
$finder = new WordFinder($list);
var_dump($finder->findWords('evli'));

And this will return

array(3) {
  [0]=>
  string(4) "evil"
  [1]=>
  string(4) "live"
  [2]=>
  string(4) "vile"
}

EDIT I've exchanged the original code with this version, as it performs much better with large wordlists. I've tested the above on my 2,2 Ghz Dual Core and it would finish 10000 calls to findWords() in a collection of 10000 words in a mere 0.08 seconds. The other version would take 207 seconds. See the revision for the old version.

Gordon
Oh my. In my answer, I kind of picked the word "shuffle" out of thin air to avoid confusion with "sorting", which might have obscured my meaning. I wasn't aware that `str_shuffle` is an established PHP function which does something completely different, namely change the order of characters *randomly*. Now I'm thinking how to resolve any confusion I may have inadvertently created.
Carl Smotricz
It's fine. He can still use `str_shuffle` to shuffle the words, because `count_chars` will return them in alphabetical anyway. There is no need for a 1:1 map.
Gordon