0
\$\begingroup\$

I have written a code that finds whether the entered words are anagrams or not. I tested and it works, but I know that there are some details that I must change or modify. So what do you think I have to change in this code?

function findAnagram (firstWord, secondWord) {
var testWord = "";
var c = 0;
while (c < secondWord.length || c < firstWord.length) {
    while (secondWord[c] == " " || firstWord[c] == " ") {
    secondWord = secondWord.replace(" ", "");
    firstWord = firstWord.replace(" ", "");
}
c++;
}

if (firstWord.length == secondWord.length) {
    for (var i = 0; i < firstWord.length; i++) {
    for (var k = 0; k < secondWord.length; k++) {
        if (firstWord[i] == secondWord[k]) {
            testWord += firstWord[i];
            secondWord = secondWord.replace(secondWord[k], "")
            break;   
        }
    }
}
}
if (firstWord == testWord){
    return "Anagram !"; 
}
else {
    return "Not an Anagram";
}
}
console.log(findAnagram("funeral", "real fun"));
\$\endgroup\$
  • \$\begingroup\$ You can also sort the characters of both of these words, and see if they match. \$\endgroup\$ – Eyal Sep 26 '18 at 23:24
2
\$\begingroup\$

Your function has a high complexity because of the 2 nested loops.

Here is my implementation. I'm not sure if it's more efficient, but I think it's more readable.

function findAndAppendCharacter(countArray, currentChar) {
    let foundAt = -1

    countArray.forEach((pair, i) => {
        if(pair.letter == currentChar) {
            foundAt = i
        }
    })


    if(foundAt == -1) {
        countArray.push({
            letter: currentChar,
            count: 1
        })

        return
    }

    countArray[foundAt].count++
}

function findAnagram(firstWord, secondWord) {
    firstWord = firstWord.replace(" ", "")
    secondWord = secondWord.replace(" ", "")

    if(firstWord.length != secondWord.length) {
        return "Not an anagram!"
    }

    let letterCountArray = {
        first: [],
        second: []
    }

    for(let i = 0; i < firstWord.length; i++) {
        findAndAppendCharacter(letterCountArray.first, firstWord.charAt(i).toLowerCase())
        findAndAppendCharacter(letterCountArray.second, secondWord.charAt(i).toLowerCase())
    }


    if(letterCountArray.first.length != letterCountArray.second.length) {
        return "Not an anagram!"
    }

    for(let i = 0; i < letterCountArray.first.length; i++) {
        let firstPair = letterCountArray.first[i]
        let secondPair = letterCountArray.second[i]

        if(letterCountArray.first.filter(pair => pair.letter == secondPair.letter && pair.count == secondPair.count).length != 1) {
            return "Not an anagram!"
        }

        if(letterCountArray.second.filter(pair => pair.letter == firstPair.letter && pair.count == firstPair.count).length != 1) {
            return "Not an anagram!"
        }
    }

    return "Anagram!"
}

I'm also curious about a better solution :)

\$\endgroup\$
1
\$\begingroup\$

Improving your whitespace removal

In order to remove spaces, you are calling string.replace once for every occurrence of " " (space) in each string. An easier way to remove whitespace in a string is to use a regular expression object with a global modifier, which will replace all matching characters in the string. Then, you can get rid of your while-loops, and your code becomes slightly easier to read.

function findAnagram (firstWord, secondWord) {
    // "/ /g" is a regular expression object that finds all spaces in a string.
    secondWord = secondWord.replace(/ /g, "");
    firstWord = firstWord.replace(/ /g, "");
    ...

You can also use the /\s/g regular expression object to replace all whitespace including tabs, newlines, etc.

Improving your algorithm

Your version (with the fixes above) works fine, but has a complexity O(n^2).

One very simple, readable way to see if two strings are anagrams is to remove whitespace, sort the letters, and then compare the sorted strings. This brings our complexity down to (depending on implementation) O(nlog(n)). Example:

// Returns the given string with whitespace removed.
function removeWhitespace(str) {
    return str.replace(/\s/g, '');
}

// Returns the given string sorted by character value.
function sortString(str) {
    return str.split('').sort().join('');
}

// Returns true if the given ASCII strings are anagrams of each other.
function isAnagram(str1, str2) {
    const trimmedStr1 = removeWhitespace(str1);
    const trimmedStr2 = removeWhitespace(str2);

    // If the strings have different lengths, there is no way for them to be anagrams.
    if (trimmedStr1.length != trimmedStr2.length) {
        return false;
    }

    // Characters should have the same capitalization before sorting.
    const sortedStr1 = sortString(trimmedStr1.toUpperCase());
    const sortedStr2 = sortString(trimmedStr2.toUpperCase());

    return sortedStr1 === sortedStr2;
}

For more examples of how to solve this problem, see this post.

Of course, if you want to compare Unicode anagrams, that's a whole different story.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.