The goal of this challenge is to write a program which takes a string (of any length) as input and displays anagrams (see these examples of anagrams) of this string, made by taking words in a dictionary (either individually or in pairs), but the anagrams don't need to be perfect.
An anagram is the result of a rearrangement of a set of characters:
ABCD
andCADB
are perfect anagrams, all the characters are present in both stringsABCD
andCADBEF
are imperfect anagrams because the charactersABCD
are present in both strings but the charactersEF
only exist in the second string
The dictionary contains 1949 words:
ability
able
aboard
etc.
By taking each word and each pair of distinct words we generate a list of candidates to compare against the input:
ability
ability able
ability aboard
ability ...
able
able aboard
able ...
...
The program must display only the strings from the previous list which are anagrams of the input string. In other words, the program needs to filter the candidates down to the imperfect anagrams of the input.
Examples
Input
Sample:
> your_program 85 "Meta Code Golf" ./dict.txt
You may take input from any method you like, be it command line arguments or stdin.
Expected output
ExCLAiMED FOOT
FrEEDOM LOCATe
(if I didn't make any mistake in my code)
Rules
Input:
n string filepath
(You may take input from any method you like, be it command line arguments or stdin)
- The first input will be an integer
n
. This is a threshold to define the minimum percentage of characters which must be present in thestring
input and the anagrams.n
will be between0
and100
, inclusive - The second input will be a string (a string with one or more words)
- The path to a file containing one word per line. The dictionary to use is available here (**), it contains 1949 common words (source). You have to save this file without the comments to keep one word per line
**: I chose to use only 1949 common words because the dictionaries like wamerican package (with Ubuntu it adds the /usr/share/dict/american-english
file) contains about 100,000 words, this would lead to 10,000,000,000 possible combinations of 2 words. It may take to much time to compute in the context of code golfing. But a program which works with 2,000 words may still work with 100,000 words if someone wants to use all the words from a complete dictionary.
Output:
- One matching anagram string per line. The matching letters between the input string and the anagram must be displayed in uppercase, and the non-matching letters must be lowercase. In the example, only 2 of the 3
e
are in uppercase, because there are only 2e
inMeta Code Golf
- You must not display the same anagram twice (eg.
ExCLAiMED FOOT
andFOOT ExCLAiMED
are both valid but they are only the result of a swap between the 2 words)
Other rules:
- Comparison between input string and anagrams:
- Lower and upper-case characters are considered as the same character when searching the anagrams
- Non-letter characters
(space),
-
, etc. are considered as one character
- Standard “loopholes” are forbidden
- Shortest code wins
Similarity index and threshold
Similarity index:
The similarity index (SI) is calculated by counting the number of times each character from a string appear in another string. So we have to compute 2 SIs if the 2 strings have different lengths.
Examples
ABCD
and CADB
are perfect anagrams, the characters are identical, the SI is 100%
ABCD
and CADBEF
:
- ABCD
in CADBEF
: the SI is 100% because all the characters of the first string exist in the second string
- CADBEF
in ABCD
: the SI is 4/6 because ABCD
are present in the second string (and not E
and F
)
You have to ensure that you compare the input with the word and the word with the input, otherwise the word AAABBBCCCDDDEEE (etc.)
may match the vast majority of the words. So we have to check that the 2 SIs are greater or equal than the threshold in order to accept an anagram.
Example of SI function (pseudo-code):
function SI(a, b) {
s_i = 0
foreach (character in a) {
if (character exists in b) {
remove the character in b /* avoid to find several times "AAAA" in "A" */
s_i++
}
}
return(s_i / length(a))
}
Threshold
The threshold acts as a filter to display only the anagrams which SI is greater or equal than the threshold.
To apply the threshold, we must use this function twice:
if ((SI(input, candidate) >= threshold) && (SI(candidate, input) >= threshold)) {/* anagram is ok */}
Examples:
Threshold = 100
> program 100 "explanation" ./dict.txt
EXPLANATION
There is only one result because there is no perfect anagram for Explanation, except the word itself.
Threshold = 90
> program 90 "explanation" ./dict.txt
ALONE PAINT
EXPLAIN NOT
EXPLANATION
NATION PALE
Threshold = 75
> program 75 "explanation" ./dict.txt
AbLE cONTAIN
AbLE NATION
AbOuT EXPLAIN
AcT EXPLAIN
AcTION ALoNE
AcTION ANgLE
...
Threshold = 0
> program 0 "Meta Code Golf" ./dict.txt
AbILiTy
AbILiTy AblE
AbILiTy AbOard
AbILiTy AbOut
...
It will display all the words and all the combination of words from the dictionary (because all the SIs are greater or equal than the threshold).
Random example
> program 85 "Beyonce Knowles" ./dict.txt
BEtWEEN COLONY
COWBOY SENtENcE
I was inspired by a french TV program named Le Complot where they make funny correlations between two unrelated persons, ideas, etc. For example, they showed that the soccer player Pastore is an anagram of Apotres (the french word for Apostles) in order to link Zlatan Ibrahimovic to Catholic Church.