Maybe it's my liberal arts background but I love words and word games. I have a constant pile of crosswords and enjoy tormenting my kids (and wife) with puns. I am also fascinated with word hacks like palindromes and anagrams. An anagram is where you take a word like 'pot' and rearrange the letters to spell another word like 'opt' or 'top'. Short words are easy to do in your head. So I thought why not get PowerShell to do some of the letter crunching for me.
ManageEngine ADManager Plus - Download Free Trial
Exclusive offer on ADManager Plus for US and UK regions. Claim now!
Remember, the purpose of these articles is not the end result but the process and the techniques. Let's start with a word.
$w = "angle"
I know that this word should match some of the words in this list.
#should match Angle,glean, and genal $l = "Angle","aaa","glean","genal","angles"
In an anagram, it has the same letters as the source word, just in a different order. So I figured I could turn the source word into a character array and compare the array of potential targets. I went through a number of experiments but finally settled on this.
$a = (($w.GetEnumerator() | sort) -join '')
In essence I've take the letters in the word, 'angle', sorted them, then rejoined into a single string, 'aegln'. If it helps, you could think of this as a type of hash. Now, I can go through each word in my potential list, perform the same type of hashing operation and compare.
$l | where {$a -eq (($_.GetEnumerator() | sort) -join '')}
If you try this you should get the expected results. But the whole point is to discover anagrams for a given word. And for that I need a big list of words.
I found one at from https://github.com/dwyl/english-words that has over 466K entries. I downloaded a copy to my Scripts folder. Given the size, I figured it would be easier to test my process on a subset of words.
Get-content c:\scripts\dictionary.txt | select -first 50000 | where {($a -eq (($_.GetEnumerator() | sort) -join ''))}
This gave me 3 anagrams in just under 15 seconds. Then I realized, it doesn't make any sense to compare any words from the list that don't have the same number of characters.
Get-content c:\scripts\dictionary.txt | select -first 50000 | where { ($_.length -eq $w.length) -and ($a -eq (($_.GetEnumerator() | sort) -join ''))}
That took 2.5 seconds! Let's try the whole word list.
$w = "angel" $a = ($w.getenumerator() | sort) -join "" Get-content c:\scripts\dictionary.txt | where {($_.length -eq $w.length) -AND ((($_.getenumerator() | sort) -join "") -eq $a )}
That took about 21 seconds.
By the way, I also tested with getting the word list first and then piping that to Where-Object.
$dict = Get-content c:\scripts\dictionary.txt $dict | where {($_.length -eq $w.length) -AND ((($_.getenumerator() | sort) -join "") -eq $a )}
This was not any faster. It took over 9 seconds to read in the 466K words and then almost 2 minutes to filter.
Now that I have settled on some core code, let's wrap it up in a function.
https://gist.github.com/jdhitsolutions/1a05db07a3bc1b5c93728755f631b34e
The function is a gist on my GitHub repo and defines a function called Get-Anagram. You will need a word list. I've set a default value for mine.
Usage, is pretty simple. Specify a word and a word list. My function will write a custom object to the pipeline with a property of all the anagrams. Here are a few examples of the function in action.
Yeah, I don't expect you to have an urgent business need to find an anagram for 'danger' ('ranged' in case you were curious) but you might need to process a large log file, understand filtering or get an example of how to write a function.
Or maybe you just want to have a little fun. Enjoy!
Function doesn’t work correctly… Here is example:
$w = “Glean”
$a = (($w.GetEnumerator() | sort) -join “”)
$a
And this is the reason:
[char[]]”$a” | % {Write-host “$_ $([int][char]$_)”}
Have fun and happy scripting 😉
Halis
Yeah, I’m not taking case into account.
Word List – Scrabble Dictionary.
Randomly grab 7 tiles (real tiles, not a function).
Try to come up with as many words as you can.
Run Get-Anagram with tiles (all and in different combinations)
You now have a scrabble trainer.