jiaoziren
jiaoziren

Reputation: 1329

Anagrams finder in javascript

I am supposed to write a program in JavaScript to find all the anagrams within a series of words provided. e.g.:

monk, konm, nkom, bbc, cbb, dell, ledl, llde

The output should be categorised into rows:

1. monk konm, nkom;
2. bbc cbb;
3. dell ledl, llde;

I already sorted them into alphabetical order and put them into an array. i.e.:

kmno kmno bbc bbc dell dell

However I am stuck in comparing and finding the matching anagram within the array.

Any help will be greatly appreciated.

Upvotes: 28

Views: 126671

Answers (30)

Muzammil KT
Muzammil KT

Reputation: 41

3 line of code is enough for this. Please have a look.

const arr = ["monk", "konm", "nkom", "bbc", "cbb", "dell", "ledl", "llde"];

let a = {};
arr.forEach((word,index) => {
    const sortedText = word.split("").sort().join("");
    a[sortedText]=[...(a[sortedText]||[]),arr[index]]
});

console.log([Object.values(a)])

Upvotes: 0

Bruno João
Bruno João

Reputation: 5535

If you order the letters for the words you can compare them easily:

const list = ['monk', 'konm', 'nkom', 'bbc', 'cbb', 'dell', 'ledl', 'llde'];

// creates a map for each anagram list
const anagramsMap = list.reduce((acc, curr, index) => {
    const sortedWord = curr.split('').sort().join('');
    return {...acc, [sortedWord]: [curr, ...acc[sortedWord ] || []]};
}, {});

// outputs one anagrams list per line
Object.values(anagramsMap ).forEach(items => console.log(items.join(', ')));

Upvotes: 0

Arush
Arush

Reputation: 25

const str1 ="1123451"
const str2 = "2341151"

function anagram(str1,str2) {
    let count = 0;
    if (str1.length!==str2.length) { return false;}
    for(i1=0;i1<str1.length; i1++) {
        for (i2=0;i2<str2.length; i2++) {
            if (str1[i1]===str2[i2]){
                count++;
                break;
            }
        } 
    }
    if (count===str1.length) { return true}
}
anagram(str1,str2)

Upvotes: 1

priolo priolus
priolo priolus

Reputation: 372

function isAnagram(item1, item2) {
    if (!item1 || !item2 || item1 == item2 || item1.length != item2.length) return false
    const ret = item1.split("").reduce((acc, c) => {
        const index = acc.indexOf(c);
        if (index > -1) acc.splice(index, 1)
        return acc
    }, item2.split(""))
    return ret.length == 0
}

console.log( isAnagram("pippo", "opppi") )

Upvotes: 0

Sadqain Kazmi
Sadqain Kazmi

Reputation: 29

function anagram(string1, string2) {
    if (string1.toLowerCase() === string2.toLowerCase()) {
       return 'anagram'
    } else if (string1.length === string2.length) {

    if (string1.toLowerCase().split("").sort().join() === string2.toLowerCase().split("").sort().join()) {
      return 'anagram'
    }
  } else { return 'not a anagram' }
}



console.log(anagram('listen','silent'))

Upvotes: 1

Kashyap
Kashyap

Reputation: 107

Here, I would first convert list of words in to anagram object. I am pushing anagram words in to new object where key is anagram. if anagram is already found in the object then I would concat the new word.

At last I am just taking out the values of result object. Code is self explanatory and short.

const input = "monk, konm, nkom, bbc, cbb, dell, ledl, llde";

const anagramCreater = (data) => { return data.split("").sort().join("");}

const anagram = input
.split(", ")
.reduce((acc, word) => {
  const anagramWord = anagramCreater(word);
  acc[anagramWord] = acc[anagramWord] 
    ? `${acc[anagramWord]},${word}` 
    : word;
  return acc;
}, {});
console.log(Object.values(anagram).join("\n"));

Upvotes: 0

sajad.sharhani
sajad.sharhani

Reputation: 43

the answer that comes to my mind:

function anagrams(stringA, stringB) {
  const aCharMap = buildCharMap(stringA);
  const bCharMap = buildCharMap(stringB);

  if (Object.keys(aCharMap).length !== Object.keys(bCharMap).length) {
    return false;
  }

  for (let char in aCharMap) {
    if (aCharMap[char] !== bCharMap[char]) {
      return false;
    }
  }

  return true;
}

helper function:

function buildCharMap(str) {
  const charMap = {};

  for (let char of str.replace(/[^\w]/g, '')) {
    charMap[char] = charMap[char] + 1 || 1;
  }

  return charMap;
}

but if you're looking for the easiest way:

function anagrams(stringA, stringB) {
  return cleanString(stringA) === cleanString(stringB);
}


function cleanString(str) {
  return str.replace(/[^\w]/g, '').toLowerCase().split('').sort().join('');
}

Upvotes: 0

Sarthak Goel
Sarthak Goel

Reputation: 1

const arr = ['monk', 'konm', 'nkom', 'bbc', 'cbb', 'dell', 'ledl', 'llde'];
let anagram = {};

for (let i = 0; i<arr.length; i++){
  const word = arr[i];
  const sortedWord = word.split("").sort().join("");
  let tempArray = [];
  if(anagram[sortedWord]){
    tempArray = anagram[sortedWord].length==1?anagram[sortedWord]:[...anagram[sortedWord]];
    tempArray.push(word);
    anagram[sortedWord] = tempArray;
  }else{
    anagram[sortedWord] = [word];
  }
}
console.log(Object.values(anagram));

Upvotes: 0

Vivek Kumar
Vivek Kumar

Reputation: 51

let validAnagram = (firstString, secondString) => {
    if (firstString.length !== secondString.length) {
        return false;
    }

    let secondStringArr = secondString.split('');

    for (var char of firstString) {
        charIndexInSecondString = secondString.indexOf(char);
        if (charIndexInSecondString === -1) {
            return false;
        }
        secondString = secondString.replace(char, '');
    }

    
    return true;
}

Upvotes: 0

Ganesh Shetty
Ganesh Shetty

Reputation: 1

 function isAnagaram(str1, str2){
        if(str1.length!== str2.length){
            return false;
        }
        var obj1 = {};
        var obj2 = {};
        for(var arg of str1){
            obj1[arg] =  (obj1[arg] || 0 ) + 1 ;
        }
        for(var arg of str2){
            obj2[arg] =  (obj2[arg] || 0 ) + 1 ;
        }
    
        for( var key in obj1){
            if(obj1[key] !== obj2[key]){
                return false;
            }
        }
        return true;
    }
    
    console.log(isAnagaram('texttwisttime' , 'timetwisttext'));

Upvotes: 0

Vladi4
Vladi4

Reputation: 1

const getAnagrams = (...args) => {
    const anagrams = {};

    args.forEach((arg) => {        
        const letters = arg.split("").sort().join("");

        if (anagrams[letters]) {
            anagrams[letters].push(arg);
        } else {
            anagrams[letters] = [arg];
        }
    });
    
    return Object.values(anagrams);
}

Upvotes: 0

Drashti Trivedi
Drashti Trivedi

Reputation: 31

Another example only for comparing 2 strings for an anagram.

   function anagram(str1, str2) {
      if (str1.length !== str2.length) {
        return false;
      } else {
        if (
          str1.toLowerCase().split("").sort().join("") ===
          str2.toLowerCase().split("").sort().join("")
        ) {
          return "Anagram";
        } else {
          return "Not Anagram";
        }
      }
    }
    
    console.log(anagram("hello", "olleh"));
    console.log(anagram("ronak", "konar"));

Upvotes: 1

liron_hazan
liron_hazan

Reputation: 1546

Probably not the most efficient way, but a clear way around using es6

function sortStrChars(str) {
  if (!str) {
    return;
  }
  str = str.split('');
  str = str.sort();
  str = str.join('');
  return str;
}

const words = ["dell", "ledl", "abc", "cba", 'boo'];

function getGroupedAnagrams(words) {
  const anagrams = {}; // {abc:[abc,cba], dell:[dell, ledl]}
  words.forEach((word) => {
    const sortedWord = sortStrChars(word);
    if (anagrams[sortedWord]) {
      return anagrams[sortedWord].push(word);
    }
    anagrams[sortedWord] = [word];
  });
  return anagrams;
}

const groupedAnagrams = getGroupedAnagrams(words);
for (const sortedWord in groupedAnagrams) {
  console.log(groupedAnagrams[sortedWord].toString());
}

Upvotes: 9

Tim B&#252;the
Tim B&#252;the

Reputation: 63744

Here is my take:

var input = "monk, konm, bbc, cbb, dell, ledl";
var words = input.split(", ");

for (var i = 0; i < words.length; i++) {

  var word = words[i];
  var alphabetical = word.split("").sort().join("");

  for (var j = 0; j < words.length; j++) {

    if (i === j) {
      continue;
    }

    var other = words[j];
    if (alphabetical === other.split("").sort().join("")) {
      console.log(word + " - " + other + " (" + i + ", " + j + ")");
    }
  }
}

where the output would be (the word, the match and the index of both):

monk - konm (0, 1)
konm - monk (1, 0)
bbc - cbb (2, 3)
cbb - bbc (3, 2)
dell - ledl (4, 5)
ledl - dell (5, 4)

To get the characters in the in alphabetical order, I used split("") ot get an array, called sort() and used join("") to get a string from the array.

Upvotes: 22

Mukul Reksh
Mukul Reksh

Reputation: 11

function findAnagram(str1, str2) {

  let mappedstr1 = {}, mappedstr2 = {};

  for (let item of str1) {
    mappedstr1[item] = (mappedstr1[item] || 0) + 1;
  }

  for (let item2 of str2) {
    mappedstr2[item2] = (mappedstr2[item2] || 0) + 1;
  }

  for (let key in mappedstr1) {
    if (!mappedstr2[key]) {
      return false;
    }

    if (mappedstr1[key] !== mappedstr2[key]) {
      return false;
    }
  }

  return true;
}
console.log(findAnagram("hello", "hlleo"));

Upvotes: 1

Karo Gevorgyan
Karo Gevorgyan

Reputation: 11

function findAnagrams (str, arr){
let newStr = "";
let output = [];

for (let i = 0; i < arr.length; i++) {
  for (let j = 0; j < arr[i].length; j++) {
    for (let k = 0; k < str.length; k++) {
      if (str[k] === arr[i][j] && str.length === arr[i].length) {
        newStr += arr[i][j];
      }
    }
  } if(newStr.length === str.length){
    output.push(newStr);
    newStr = "";
  }
  }
  return output;
}

Upvotes: 0

marcobiedermann
marcobiedermann

Reputation: 4915

  1. Compare string length, if not equal, return false
  2. Create character Hashmap which stores count of character in strA e.g. Hello --> {H: 1, e: 1, l: 2, o: 1}
  3. Loop over the second string and lookup the current character in Hashmap. If not exist, return false, else decrement the value by 1
  4. If none of the above return falsy, it must be an anagram

Time complexity: O(n)

function isAnagram(strA: string, strB: string): boolean {
  const strALength = strA.length;
  const strBLength = strB.length;
  const charMap = new Map<string, number>();

  if (strALength !== strBLength) {
    return false;
  }

  for (let i = 0; i < strALength; i += 1) {
    const current = strA[i];

    charMap.set(current, (charMap.get(current) || 0) + 1);
  }

  for (let i = 0; i < strBLength; i += 1) {
    const current = strB[i];

    if (!charMap.get(current)) {
      return false;
    }

    charMap.set(current, charMap.get(current) - 1);
  }

  return true;
}

Upvotes: 1

Lokesh K V
Lokesh K V

Reputation: 56

function isAnagram(str1, str2){
  let count = 0;

  if (str1.length !== str2.length) {
    return false;
  } else {
    let val1 = str1.toLowerCase().split("").sort();
    let val2 = str2.toLowerCase().split("").sort();
    for (let i = 0; i < val2.length; i++) {
      if (val1[i] === val2[i]) {
        count++;
      }
    }
  if (count == str1.length) {
    return true;
   }
 }
 return false;
}

console.log(isAnagram("cristian", "Cristina"))

Upvotes: 0

kiran goud
kiran goud

Reputation: 843

If you just need count of anagrams

const removeDuplicatesAndSort = [...new Set(yourString.split(', '))].map(word => word.split('').sort().join())
const numberOfAnagrams = removeDuplicatesAndSort.length  - [...new Set(removeDuplicatesAndSort)].length

Upvotes: 1

Neha Kumari
Neha Kumari

Reputation: 11

    let words = ["dell", "ledl","del", "abc", "cba", 'boo'];
    
    //sort each item 
    function sortArray(data){
      var r=data.split('').sort().join().replace(/,/g,'');
      return r;
    }
    
    var groupObject={};
    words.forEach((item)=>{
    let sorteditem=sortArray(item);
    
//Check current item is in the groupObject or not.
    //If not then add it as an array
    //else push it to the object property
    if(groupObject[sorteditem])
      return groupObject[sorteditem].push(item);
    groupObject[sorteditem]=[sorteditem];
    });
    
    //to print the result
    for(i=0;i<Object.keys(groupObject).length;i++)
       document.write(groupObject[Object.keys(groupObject)[i]] + "<br>");
    
    /* groupObject value: 
    abc: (2) ["abc", "cba"]
    boo: ["boo"]
    del: ["del"]
    dell: (2) ["dell", "ledl"]
    
    OUTPUT:
    ------
    dell,ledl
    del
    abc,cba
    boo
    */

Upvotes: 1

Neha Kumari
Neha Kumari

Reputation: 11

/*This is good option since 
  logic is easy,
  deals with duplicate data,
  Code to check anagram in an array,
  shows results in appropriate manner,
  function check can be separately used for comparing string in this regards with all benefits mentioned above.
  */

var words = ["deuoll", "ellduo", "abc","dcr","frt", "bu","cba","aadl","bca","elduo","bac","acb","ub","eldou","ellduo","ert","tre"];
var counter=1;
var ele=[];
function check(str1,str2)
{   
    if(str2=="")
    return false;
    if(str1.length!=str2.length)
      return false;
    var r1=[...(new Set (str1.split('').sort()))]; 
    var r2=[...(new Set (str2.split('').sort()))]; 
    var flag=true;

    r1.forEach((item,index)=>
    {
    if(r2.indexOf(item)!=index)
    { flag=false;}
    });

    return flag;
}

var anagram=function ()
{
  for(var i=0;i<words.length && counter!=words.length ;i++)
  {
  if(words[i]!="")
  {
    document.write("<br>"+words[i]+":");
    counter++;
    }
    for(var j=i+1;j<words.length && counter !=words.length+1;j++)
    {
       if(check(words[i],words[j]))
       {
              ele=words[j];
             document.write(words[j]+"&nbsp");
             words[j]="";
              counter++;   
       }
     }
  }
}
anagram();

Upvotes: 0

Ellie Maynard
Ellie Maynard

Reputation: 123

My solution has more code, but it avoids using .sort(), so I think this solution has less time complexity. Instead it makes a hash out of every word and compares the hashes:

const wordToHash = word => {
  const hash = {};
  // Make all lower case and remove spaces
  [...word.toLowerCase().replace(/ /g, '')].forEach(letter => hash[letter] ? hash[letter] += 1 : hash[letter] = 1);
  return hash;
}
const hashesEqual = (obj1, obj2) => {
  const keys1 = Object.keys(obj1), keys2 = Object.keys(obj2);
  let match = true;
  if(keys1.length !== keys2.length) return false;
  for(const key in keys1) { if(obj1[key] !== obj2[key]) match = false; break; }
  return match;
}
const checkAnagrams = (word1, word2) => {
  const hash1 = wordToHash(word1), hash2 = wordToHash(word2);
  return hashesEqual(hash1, hash2);
}
console.log( checkAnagrams("Dormitory", "Dirty room") );

Upvotes: 0

Chris
Chris

Reputation: 21

My two cents.

This approach uses XOR on each character in both words. If the result is 0, then you have an anagram. This solution assumes case sensitivity.

let first = ['Sower', 'dad', 'drown', 'elbow']
let second = ['Swore', 'add', 'down', 'below']

// XOR all characters in both words
function isAnagram(first, second) {
  // Word lengths must be equal for anagram to exist
  if (first.length !== second.length) {
    return false
  }

  let a = first.charCodeAt(0) ^ second.charCodeAt(0)

  for (let i = 1; i < first.length; i++) {
    a ^= first.charCodeAt(i) ^ second.charCodeAt(i)
  }

  // If a is 0 then both words have exact matching characters
  return a ? false : true
}

// Check each pair of words for anagram match
for (let i = 0; i < first.length; i++) {
  if (isAnagram(first[i], second[i])) {
    console.log(`'${first[i]}' and '${second[i]}' are anagrams`)
  } else {
    console.log(`'${first[i]}' and '${second[i]}' are NOT anagrams`)
  }
}

Upvotes: 2

user32961
user32961

Reputation: 1

function checkAnagram(str1, str2) {
    str1 = str1.toLowerCase();
    str2 = str2.toLowerCase();
    let sum1 = 0;
    let sum2 = 0;
    for (let i = 0; i < str1.length; i++) {
        sum1 = sum1 + str1.charCodeAt(i);
    }
    for (let j = 0; j < str2.length; j++) {
        sum2 = sum2 + str2.charCodeAt(j);
    }
    if (sum1 === sum2) {
        return "Anagram";
    } else {
        return "Not Anagram";
    }
}

Upvotes: -1

Ronak07
Ronak07

Reputation: 894

Best and simple way to solve is using for loops and traversing it to each string and then store their result in object.

Here is the solution :-

function anagram(str1, str2) {
    if (str1.length !== str2.length) {
        return false;
    }
    const result = {};
    for (let i=0;i<str1.length;i++) {
        let char = str1[i];
        result[char] = result[char] ? result[char] += 1 : result[char] = 1;
    }

    for (let i=0;i<str2.length;i++) {
        let char = str2[i];
        if (!result[char]) {
            return false;
        }
        else {
            result[char] = -1;
        }
    }
    return true;
}

console.log(anagram('ronak','konar'));

Upvotes: 4

Satish Kale
Satish Kale

Reputation: 11

i have recently faced this in the coding interview, here is my solution.

    function group_anagrams(arr) {
      let   sortedArr = arr.map(item => item.split('').sort().join(''));
      let setArr = new Set(sortedArr);
      let reducedObj = {};
      for (let setItem of setArr) {
        let indexArr = sortedArr.reduce((acc, cur, index) => {
          if (setItem === cur) {
            acc.push(index);
          }
          return acc;
        }, []);
        reducedObj[setItem] = indexArr;
      }
      let finalArr = [];
      for (let reduceItem in reducedObj) {
        finalArr.push(reducedObj[reduceItem].map(item => arr[item]));
      }
      return finalArr;
    }
    group_anagrams(['car','cra','rca', 'cheese','ab','ba']);

output will be like

[
  ["car", "cra", "rca"],
  ["cheese"],
  ["ab", "ba"]
]

Upvotes: 0

stahlstalin
stahlstalin

Reputation: 1

Here is my solution which addresses a test case where the input strings which are not anagrams, can be removed from the output. Hence the output contains only the anagram strings. Hope this is helpful.

/**
 * Anagram Finder
 * @params {array} wordArray
 * @return {object}
 */
function filterAnagram(wordArray) {
  let outHash = {};
  for ([index, word] of wordArray.entries()) {
    let w = word.split("").sort().join("");
    outHash[w] = !outHash[w] ? [word] : outHash[w].concat(word);
  }
  let filteredObject = Object.keys(outHash).reduce(function(r, e) {
    if (Object.values(outHash).filter(v => v.length > 1).includes(outHash[e])) r[e] = outHash[e]
    return r;
  }, {});

  return filteredObject;
}

console.log(filterAnagram(['monk', 'yzx','konm', 'aaa', 'ledl', 'bbc', 'cbb', 'dell', 'onkm']));

Upvotes: 0

bajran
bajran

Reputation: 1503

Simple Solution

function anagrams(stringA, stringB) {
    return cleanString(stringA) === cleanString(stringB);
}

function cleanString(str) {
    return str.replace(/[^\w]/g).toLowerCase().split('').sort().join()
}   

anagrams('monk','konm')

If it is anagrams function will return true otherwise false

Upvotes: 18

ravi
ravi

Reputation: 21

var check=true;
var str="cleartrip";
var str1="tripclear";
if(str.length!=str1.length){
console.log("Not an anagram");

check=false;
}
console.log(str.split("").sort());
console.log("----------"+str.split("").sort().join(''));
if(check){
if((str.split("").sort().join(''))===((str1.split("").sort().join('')))){
console.log("Anagram")
}
else{
console.log("not a anagram");
}
}

Upvotes: 0

Thilina Hasantha
Thilina Hasantha

Reputation: 130

Another solution for isAnagram using reduce

const checkAnagram = (orig, test) => {
  return orig.length === test.length 
    && orig.split('').reduce(
      (acc, item) => {
        let index = acc.indexOf(item);
        if (index >= 0) {
          acc.splice(index, 1);
          return acc;
        }
        throw new Error('Not an anagram');
      },
      test.split('')
    ).length === 0;
};

const isAnagram = (tester, orig, test) => {
  try {
    return tester(orig, test);  
  } catch (e) {
    return false;
  }
}

console.log(isAnagram(checkAnagram, '867443', '473846'));
console.log(isAnagram(checkAnagram, '867443', '473846'));
console.log(isAnagram(checkAnagram, '867443', '475846'));

Upvotes: 0

Related Questions