Check for Anagram in 2 strings - javascript

I've created a function that checks if 2 words are anagrams, but I want to make it better. I feel the declaration of the counter after in the if statement is not quite well, if anybody have a better solution would be great.
function checkAnagram(string1, string2){
if(string1.length !== string2.length){
return false;
}
for(var i = 0; i < string1.length; i++){
if(count <= 0){
return false;
}
var count = 0;
for(var t = 0; t < string2.length; t++){
//counter = 0
if(string2[t].toLowerCase() == string1[i].toLowerCase()){
//counter++;
count++;
break;
}
}
}
return true;
}

Here is a much easier way of doing it:
var s1 = "test"
var s2 = "tset"
function testAnagram (s1, s2){
if(!s1 || !s2 || s1.length !== s2.length){return false;}
var lS1 = s1.toLowerCase();
var lS2 = s2.toLowerCase();
if(lS1 === lS2) {return false;}
var rS1 = lS1.split('').sort().join('');
var rS2 = lS2.split('').sort().join('');
return rS1 === rS2;
}
var result = testAnagram(s1, s2);
alert(result);

Your code returns true for strings 'aabb' and 'abcc', which are not anagrams. You can just sort the strings and check if they're equal:
function checkAnagram(string1, string2) {
return string1.toLowerCase().split("").sort().join("") === string2.toLowerCase().split("").sort().join("")
}

function checkAnagram(string1, string2) {
return string1.replace(/[^\w]/g,'').toLowerCase().split('').sort().join('') ===
string2.toLowerCase().replace(/[^\w]/g,'').split('').sort().join('')
}

If you don't want to use prebuild methods like .split() .sort() .join() then
function isAnagrams(stringA, stringB) {
// just to remove special char and convert it to lowercase
stringA = stringA.replace(/[^\w]/g, "").toLowerCase();
stringB = stringB.replace(/[^\w]/g, "").toLowerCase();
if (stringA.length !== stringB.length) return false;
let aCharMap = {};
let bCharMap = {};
/*
making of mapObject of both string, containing character as property and
count of that character as value
*/
for (let i = 0; i < stringA.length; i++) {
bCharMap[stringB[i]] = bCharMap[stringB[i]] + 1 || 1;
aCharMap[stringA[i]] = aCharMap[stringA[i]] + 1 || 1;
}
// checking both CharMap value
for (let q of stringB) {
if (bCharMap[q] !== aCharMap[q]) {
return false;
}
}
return true;
}
console.log(`isAnagram : ${isAnagrams('rail safety', 'fairy tales')}`)
so if you pass isAnagrams('rail safety','fairy tales'); then character map will look like this
aCharMap = { r: 1, a: 2, i: 1, l: 1, s: 1, f: 1, e: 1, t: 1, y: 1 }
bCharMap = { f: 1, a: 2, i: 1, r: 1, y: 1, t: 1, l: 1, e: 1, s: 1 }
then we will compare if they have same value or not based on that result will be decided

function isAnagram(str1, str2){
if(str1.length !== str2.length){
return false
}
let string1 = str1.toLowerCase().split('').sort().join('');
let string2 = str2.toLowerCase().split('').sort().join('');
return string1 === string2
}
isAnagram('abcdef', 'AbcFed')

Related

Soduko solving function takes forever with recursion

class SudokuSolver {
// check for string being sudoku
validate(puzzleString) {
const puzzleArr = puzzleString.split("")
const digitCheck = puzzleArr.every( val => val.match(/[1-9]/) || val.match(/\./))
const lengthCheck = puzzleArr.length == 81? true: false;
const checkString = this.checkString(puzzleString)
if(digitCheck && lengthCheck && checkString){
return "valid"
}
if(!lengthCheck){
return "Expected puzzle to be 81 characters long"
}
if(!digitCheck){
return "Invalid characters in puzzle"
}
if(!checkString){
return "Invalid puzzle string"
}
}
// check for string by digit.
checkString(puzzleString){
const puzzleArr = puzzleString.split("")
const check = puzzleArr.every((val, index) => {
let {row, column} = this.getRowColumn(index);
if(val.match(/\./)){
return true
}
if(val.match(/[1-9]/)){
column += ""
val = +val;
const rowCheck = this.checkRowPlacement(puzzleString, row, column, val)
const colCheck = this.checkColPlacement(puzzleString, row, column, val)
const sqrCheck = this.checkSquareRegionPlacement(puzzleString, row, column, val)
if(rowCheck && colCheck && sqrCheck){
return true
}
}
return false;
})
return check;
}
// check by place in array of string and returns row and column.
getRowColumn(place){
const value = +place
place += ""
let obj = {};
place.match(/\b(9|1[0-7])\b/)? obj = {row: 'B', column: value - 8}
: place.match(/1[8-9]|2[0-6]/)? obj = {row: 'C', column: value - 17}
: place.match(/2[7-9]|3[0-5]/)? obj = {row: 'D', column: value - 26}
: place.match(/3[6-9]|4[0-4]/)? obj = {row: 'E', column: value - 35}
: place.match(/4[5-9]|5[0-3]/)? obj = {row: 'F', column: value - 44}
: place.match(/5[4-9]|6[0-2]/)? obj = {row: 'G', column: value - 53}
: place.match(/6[3-9]|7[0-1]/)? obj = {row: 'H', column: value - 62}
: place.match(/7[2-9]|80/)? obj = {row: 'I', column: place - 71}
: obj = {row: 'A', column: value + 1};
return obj;
}
// check for valid inputs.
checkValues(row, column, value){
value += ""
column += ""
if(!value.match(/[1-9]/)){
return "Invalid value"
}
if(!row.match(/[A-I]/) || !column.match(/[1-9]/)){
return "Invalid coordinate"
}
return "fine"
}
// check for row(character) and return min and max value for that row.
rowAdd(row){
let arr;
switch(row){
case "A":
arr = [0, 9];
break;
case "B":
arr = [9, 18];
break;
case "C":
arr = [18, 27];
break;
case "D":
arr = [27, 36];
break;
case "E":
arr = [36, 45];
break;
case "F":
arr = [45, 54];
break;
case "G":
arr = [54, 63];
break;
case "H":
arr = [63, 72];
break;
case "I":
arr = [72, 81];
break;
}
return arr;
}
//check placement by row
checkRowPlacement(puzzleString, row, column, value) {
const [min, max] = this.rowAdd(row)
const index = min + parseInt(column) - 1
const puzzleArr = puzzleString.split("")
for(let i = min; i < max; i++){
if(puzzleArr[i] == value){
if(i == index){
continue
}
return false
}
}
return true;
}
//check placement by col
checkColPlacement(puzzleString, row, column, value) {
const puzzleArr = puzzleString.split("")
const startIndex = parseInt(column) - 1;
const index = this.rowAdd(row)[0] + parseInt(column) - 1;
for(let i = startIndex; i < 81; i+= 9){
if(puzzleArr[i] == value){
if(index == i){
continue
}
return false;
}
}
return true
}
// check for which square does the value belongs
checkSquareRegion(row, column){
column = +column;
switch(row){
case "A": case "B": case "C":
if(column < 4){
return "0"
}
if(column < 7){
return "1"
}
if(column < 10){
return "2"
}
;
case "D": case "E": case "F":
if(column < 4){
return "3"
}
if(column < 7){
return "4"
}
if(column < 10){
return "5"
}
;
case "G": case "H": case "I":
if(column < 4){
return "6"
}
if(column < 7){
return "7"
}
if(column < 10){
return "8"
}
;
default:
return undefined
}
}
// for square check of different values. return true if value does differ then others.
checkSquareRegionPlacement(puzzleString, row, column, value) {
const puzzleArr = puzzleString.split("")
const square = +this.checkSquareRegion(row,column)
const check = this.checkValues(row, column, value)
const index = this.rowAdd(row)[0] + parseInt(column) - 1;
if(check == "fine"){
let startIndex = (square * 3)
let flag = true;
for(let i = 0; i < 3; i++){
for(let j = startIndex; j < (startIndex + 3); j++){
if((parseInt(puzzleArr[j]) == value)){
if(puzzleArr[j] == puzzleArr[index]){
continue;
} else{
flag = false
}
} else{
continue;
}
}
if(flag == false){
break;
}
startIndex += 9;
}
if(flag){
return true
}
return false;
}else {
return check;
}
}
// solve whole puzzle
solve(puzzleString) {
const validate = this.validate(puzzleString)
if(validate == "valid"){
puzzleString = this.fillSoduko(puzzleString)
} else {
return {error: validate};
}
return puzzleString;
}
// fill soduko.
fillSoduko(puzzleString) {
const puzzleArr = puzzleString.split("")
var _this = this;
fill(puzzleArr.indexOf(val => !val.match(/[1-9]/)))
function fill(index){
console.log(index)
while (index < 81 && puzzleArr[index].match(/[1-9]/)) ++index; // skip non-empty cells
if (index == 81) return true; // we filled'em all, success!
let moves = getChoices(index);
for (let m of moves) {
puzzleArr[index] = m; // try one choice
if (fill(index + 1)) // if we can solve for the next cell
return true; // then return true, success!
}
puzzleArr[index] = "."; // no move worked; we failed, clear the cell
return false;
} // and backtrack
function getChoices(index) {
const {row, column} = _this.getRowColumn(index)
let choices = [];
for (let value = 1; value <= 9; ++value) {
if (_this.checkPlaceAndValue(puzzleString, row, column, value) == true) {
choices.push(value);
}
}
return choices;
}
return puzzleArr.join("")
}
// check for place and value of the value inserted.
checkPlaceAndValue(puzzleString, row, column, value){
value = +value;
const validate = this.validate(puzzleString);
const check = this.checkValues(row, column, value);
if((check == "fine") && (validate == "valid")){
const rowCheck = this.checkRowPlacement(puzzleString, row, column, value)
const colCheck = this.checkColPlacement(puzzleString, row, column, value)
const sqrCheck = this.checkSquareRegionPlacement(puzzleString, row, column, value)
if(rowCheck && colCheck && sqrCheck){
return true
} else{
let obj = {};
!rowCheck ? obj = {conflict: "row"}:
!colCheck ? obj = {conflict: "column"}:
obj = {conflict: "region"};
return obj;
}
} else{
let obj = {}
validate != "valid"? obj = {error: validate}:
obj = { error: check};
return obj;
}
}
}
module.exports = SudokuSolver;
So I have portion of code above which takes for ever to process. I have to use recursion as there was no other option. Please notify me if I am doing something wrong.
The backend thought about this class method is that it takes puzzle String and automatically fills it. It checks for empty(".") value in string and then check if any(1-9) is working for it. Ofcourse there are plenty of cells empty so we get not 1 but too many number as choice. We are then checking for each choice if it completes and validate a board or not.
The first thing I note is that this:
fill(puzzleArr.indexOf(val => !val.match(/[1-9]/)))
should be:
fill(puzzleArr.findIndex(val => !val.match(/[1-9]/)))
It's an easy mistake to make. indexOf is to find the first index in the array of the supplied value. findIndex is to find the first index in the array for which the supplied predicate function returns true.
On fixing that, I was able to spot that there is an error in checkSquareRegionPlacement. I haven't dug deeply into it, but using a fully solved puzzle and simply removing the final value, I tried to test a really easy case:
const complete = "172396845549287316368514297634975182927831564851462973215749638793658421486123759"
const puzzle = "17239684554928731636851429763497518292783156485146297321574963879365842148612375."
When we get into checkSquareRegionPlacement, we should be testing indices 60. 61, 62, 69, 70, 71, 78, 79, 80. But it was failing (by setting flag = false) when the index j was 25. I haven't dug in yet to see what's failing in this code, but that might at least point you in the right direction.
Overall, there are larger issues I would suggest you address:
There is a constant breaking apart of the puzzle string. You need a more useful internal format for the puzzle. Assuming that this 81-character string filled with digits (1 - 9) or dots (.) is your required input format, then I would suggest that on entering your initial function you change this to a more useful format, either a single array containing 81 characters / numbers or a 9 x 9 array of them. If you need at the very end to convert back to the string format, that's fine. In between the beginning of your initial call and its return, keep everything in a more useful format.
You repeatedly do the work of converting your plain array indices to the logical grid model and back. You could do this up front once with code something like this:
const _09 = [0, 1, 2, 3, 4, 5, 6, 7, 8];
const _03 = [0, 1, 2];
const rows = _09 .map ((i) => _09 .map ((j) => 9 * i + j))
const cols = _09 .map ((i) => _09 .map ((j) => i + 9 * j))
const squares = _03 .flatMap ((i) => _03 .map ((j) => _03 .flatMap (
(k) => _03 .map (l => 27 * i + 3 * j + 9 * k + l)
)))
const groups = Array .from ({length: 80}, (_, i) => [
rows .find (row => row .includes (i)),
cols .find (col => col .includes (i)),
squares .find (square => square .includes (i))
])
then use those stored values. For instance, "Can I place a 7 at index 80?" becomes something like groups [80] .every (g => ! g .includes (7)) (untested!). This would stop much of the fiddling with rows and columns.
This is in a class for no obvious reason. Your methods are passing the relevant data between them, so there seems to be no internal state. It seems to me that this would be better as a module.
There are other issues, too. But overall, the issue seems to be that you're working too hard. I think a strong dose of simplification should really help.

Javascript includes and map together [duplicate]

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.
Javascript objects are excellent for this purpose, since they are essentially key/value stores:
// Words to match
var words = ["dell", "ledl", "abc", "cba"];
// The output object
var anagrams = {};
for (var i in words) {
var word = words[i];
// sort the word like you've already described
var sorted = sortWord(word);
// If the key already exists, we just push
// the new word on the the array
if (anagrams[sorted] != null) {
anagrams[sorted].push(word);
}
// Otherwise we create an array with the word
// and insert it into the object
else {
anagrams[sorted] = [ word ];
}
}
// Output result
for (var sorted in anagrams) {
var words = anagrams[sorted];
var sep = ",";
var out = "";
for (var n in words) {
out += sep + words[n];
sep = "";
}
document.writeln(sorted + ": " + out + "<br />");
}
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.
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
I worked through a similar question to this today and wanted to share the results of my work. I was focused on just detecting the anagram so processing the list of words was not part of my exercise but this algorithm should provide a highly performant way to detect an anagram between two words.
function anagram(s1, s2){
if (s1.length !== s2.length) {
// not the same length, can't be anagram
return false;
}
if (s1 === s2) {
// same string must be anagram
return true;
}
var c = '',
i = 0,
limit = s1.length,
match = 0,
idx;
while(i < s1.length){
// chomp the next character
c = s1.substr(i++, 1);
// find it in the second string
idx = s2.indexOf(c);
if (idx > -1) {
// found it, add to the match
match++;
// assign the second string to remove the character we just matched
s2 = s2.substr(0, idx) + s2.substr(idx + 1);
} else {
// not found, not the same
return false;
}
}
return match === s1.length;
}
I think technically is can be solved like this:
function anagram(s1, s2){
return s1.split("").sort().join("") === s2.split("").sort().join("");
}
The reason I chose the earlier approach is that it is more performant for larger strings since you don't need to sort either string, convert to an array or loop through the entire string if any possible failure case is detected.
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());
}
I had this question in an interview. Given an array of words ['cat', 'dog', 'tac', 'god', 'act'], return an array with all the anagrams grouped together. Makes sure the anagrams are unique.
var arr = ['cat', 'dog', 'tac', 'god', 'act'];
var allAnagrams = function(arr) {
var anagrams = {};
arr.forEach(function(str) {
var recurse = function(ana, str) {
if (str === '')
anagrams[ana] = 1;
for (var i = 0; i < str.length; i++)
recurse(ana + str[i], str.slice(0, i) + str.slice(i + 1));
};
recurse('', str);
});
return Object.keys(anagrams);
}
console.log(allAnagrams(arr));
//["cat", "cta", "act", "atc", "tca", "tac", "dog", "dgo", "odg", "ogd", "gdo", "god"]
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'));
I know this is an ancient post...but I just recently got nailed during an interview on this one. So, here is my 'new & improved' answer:
var AnagramStringMiningExample = function () {
/* Author: Dennis Baughn
* This has also been posted at:
* http://stackoverflow.com/questions/909449/anagrams-finder-in-javascript/5642437#5642437
* Free, private members of the closure and anonymous, innner function
* We will be building a hashtable for anagrams found, with the key
* being the alphabetical char sort (see sortCharArray())
* that the anagrams all have in common.
*/
var dHash = {};
var sortCharArray = function(word) {
return word.split("").sort().join("");
};
/* End free, private members for the closure and anonymous, innner function */
/* This goes through the dictionary entries.
* finds the anagrams (if any) for each word,
* and then populates them in the hashtable.
* Everything strictly local gets de-allocated
* so as not to pollute the closure with 'junk DNA'.
*/
(function() {
/* 'dictionary' referring to English dictionary entries. For a real
* English language dictionary, we could be looking at 20,000+ words, so
* an array instead of a string would be needed.
*/
var dictionaryEntries = "buddy,pan,nap,toot,toto,anestri,asterin,eranist,nastier,ratines,resiant,restain,retains,retinas,retsina,sainter,stainer,starnie,stearin";
/* This could probably be refactored better.
* It creates the actual hashtable entries. */
var populateDictionaryHash = function(keyword, newWord) {
var anagrams = dHash[keyword];
if (anagrams && anagrams.indexOf(newWord) < 0)
dHash[keyword] = (anagrams+','+newWord);
else dHash[keyword] = newWord;
};
var words = dictionaryEntries.split(",");
/* Old School answer, brute force
for (var i = words.length - 1; i >= 0; i--) {
var firstWord = words[i];
var sortedFirst = sortCharArray(firstWord);
for (var k = words.length - 1; k >= 0; k--) {
var secondWord = words[k];
if (i === k) continue;
var sortedSecond = sortCharArray(secondWord);
if (sortedFirst === sortedSecond)
populateDictionaryHash(sortedFirst, secondWord);
}
}/*
/*Better Method for JS, using JS Array.reduce(callback) with scope binding on callback function */
words.reduce(function (prev, cur, index, array) {
var sortedFirst = this.sortCharArray(prev);
var sortedSecond = this.sortCharArray(cur);
if (sortedFirst === sortedSecond) {
var anagrams = this.dHash[sortedFirst];
if (anagrams && anagrams.indexOf(cur) < 0)
this.dHash[sortedFirst] = (anagrams + ',' + cur);
else
this.dHash[sortedFirst] = prev + ','+ cur;
}
return cur;
}.bind(this));
}());
/* return in a nice, tightly-scoped closure the actual function
* to search for any anagrams for searchword provided in args and render results.
*/
return function(searchWord) {
var keyToSearch = sortCharArray(searchWord);
document.writeln('<p>');
if (dHash.hasOwnProperty(keyToSearch)) {
var anagrams = dHash[keyToSearch];
document.writeln(searchWord + ' is part of a collection of '+anagrams.split(',').length+' anagrams: ' + anagrams+'.');
} else document.writeln(searchWord + ' does not have anagrams.');
document.writeln('<\/p>');
};
};
Here is how it executes:
var checkForAnagrams = new AnagramStringMiningExample();
checkForAnagrams('toot');
checkForAnagrams('pan');
checkForAnagrams('retinas');
checkForAnagrams('buddy');
Here is the output of the above:
toot is part of a collection of 2
anagrams: toto,toot.
pan is part of a collection of 2
anagrams: nap,pan.
retinas is part of a collection of 14
anagrams:
stearin,anestri,asterin,eranist,nastier,ratines,resiant,restain,retains,retinas,retsina,sainter,stainer,starnie.
buddy does not have anagrams.
My solution to this old post:
// Words to match
var words = ["dell", "ledl", "abc", "cba"],
map = {};
//Normalize all the words
var normalizedWords = words.map( function( word ){
return word.split('').sort().join('');
});
//Create a map: normalizedWord -> real word(s)
normalizedWords.forEach( function ( normalizedWord, index){
map[normalizedWord] = map[normalizedWord] || [];
map[normalizedWord].push( words[index] );
});
//All entries in the map with an array with size > 1 are anagrams
Object.keys( map ).forEach( function( normalizedWord , index ){
var combinations = map[normalizedWord];
if( combinations.length > 1 ){
console.log( index + ". " + combinations.join(' ') );
}
});
Basically I normalize every word by sorting its characters so stackoverflow would be acefkloorstvw, build a map between normalized words and the original words, determine which normalized word has more than 1 word attached to it -> That's an anagram.
Maybe this?
function anagram (array) {
var organized = {};
for (var i = 0; i < array.length; i++) {
var word = array[i].split('').sort().join('');
if (!organized.hasOwnProperty(word)) {
organized[word] = [];
}
organized[word].push(array[i]);
}
return organized;
}
anagram(['kmno', 'okmn', 'omkn', 'dell', 'ledl', 'ok', 'ko']) // Example
It'd return something like
{
dell: ['dell', 'ledl'],
kmno: ['kmno', okmn', 'omkn'],
ko: ['ok', ko']
}
It's a simple version of what you wanted and certainly it could be improved avoiding duplicates for example.
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`)
}
}
function isAnagram(str1, str2) {
var str1 = str1.toLowerCase();
var str2 = str2.toLowerCase();
if (str1 === str2)
return true;
var dict = {};
for(var i = 0; i < str1.length; i++) {
if (dict[str1[i]])
dict[str1[i]] = dict[str1[i]] + 1;
else
dict[str1[i]] = 1;
}
for(var j = 0; j < str2.length; j++) {
if (dict[str2[j]])
dict[str2[j]] = dict[str2[j]] - 1;
else
dict[str2[j]] = 1;
}
for (var key in dict) {
if (dict[key] !== 0)
return false;
}
return true;
}
console.log(isAnagram("hello", "olleh"));
I have an easy example
function isAnagram(strFirst, strSecond) {
if(strFirst.length != strSecond.length)
return false;
var tempString1 = strFirst.toLowerCase();
var tempString2 = strSecond.toLowerCase();
var matched = true ;
var cnt = 0;
while(tempString1.length){
if(tempString2.length < 1)
break;
if(tempString2.indexOf(tempString1[cnt]) > -1 )
tempString2 = tempString2.replace(tempString1[cnt],'');
else
return false;
cnt++;
}
return matched ;
}
Calling function will be isAnagram("Army",Mary);
Function will return true or false
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
*/
Compare string length, if not equal, return false
Create character Hashmap which stores count of character in strA e.g. Hello --> {H: 1, e: 1, l: 2, o: 1}
Loop over the second string and lookup the current character in Hashmap. If not exist, return false, else decrement the value by 1
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;
}
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"));
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"));
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)
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'));
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");
}
}
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']));
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"]
]
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") );
/*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();
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
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"))
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;
}
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);
}
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'));
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;
}

Recursive function to return each character in Input

i am trying to use recursion to return each character in a string. However, the output is not
//We define a function with input parameter.
function countCharInString(string) {
//vi Define an empty objec
const result = {};
//we loop through the length of string
for (let i = 0; i < string.length; i++) {
//create another variable for each element in string
const ch = string[i];
//BASE CASE: if string is empty, return Object with nothing
if (!result[ch]) {
return result[ch]=0;
} else {
//RECURSION: 1 plus whatever the length of the substring from the next character onwards is
return countCharInString(result[ch] + 1)
}
}
}
console.log(countCharInString("Vi skal tælle bogstaver"))
the output should be the following:
var result = {
l : 3,
a : 2,
e : 2,
s : 2,
t : 2,
v : 2,
b: 1,
i : 1,
k : 1,
o : 1,
r : 1,
æ : 1
};
i would suggest to do it with a simple reduce like so
var inputString = 'donald duck';
var result = inputString.split('').reduce((acc, char, index) => {
if (acc[char] !== undefined) {
acc[char] = acc[char] + 1;
}
else {
acc = { ...acc, [char]: 1 }
}
return acc
}, {})
see: https://jsfiddle.net/yswu91zh/21/
Only recursion would not give you the output that you are asking for. After recursively counting character you have to sort it by frequency and then by character. I have excluded a bunch of punctuation with space from counting, if you want exclude more just add it to the punctuation string. You have to use String.prototype.localeCompare() method to compare the characters. This method compares two strings in the current locale. As you are using Danish language you have to specify locale as da.
const punctuations = '.,:;!? ';
const countCharInString = (str, p = {}) => {
if (str.length === 0) return p;
const key = str[0].toLowerCase();
if (!punctuations.includes(key)) {
if (!p[key]) p[key] = 1;
else p[key] += 1;
}
return countCharInString(str.slice(1), p);
};
const cmp = (x, y) => {
if (x[1] === y[1]) {
return x[0].localeCompare(y[0], 'da');
}
return x[1] < y[1] ? 1 : -1;
};
const ret = Object.fromEntries(
Object.entries(countCharInString('Vi skal tælle bogstaver')).sort(cmp)
);
console.log(ret);

Shortest path algorithm js error

I am quite new into JS and a friend of mine sent me this fiddle
function shortestPath(g, s) {
g.vertexes.forEach(function(u) {
u.dist = Infinity;
u.prev = null;
});
s.dist = 0;
for (var i = 0; i < g.vertexes.length - 1; i++) {
g.edges.forEach(function(e) {
update(e);
});
}
printResult(); }
function update(e) {
var u = e.from;
var v = e.to;
if (v.dist > u.dist + e.data) {
v.dist = u.dist + e.data;
v.prev = u;
} }
var result = [];
function printResult() {
var str = '';
debugger;
for (var i = 0; i < result[0].length; i++) {
for (var j = 0; j < result.length; j++) {
str += result[i][j] + ' ';
}
console.log(str);
str = '';
} }
function printGraph(G) {
var a = [];
G.vertexes.forEach(function(u) {
a.push(u.dist);
});
result.push(a); }
function Graph(options) {
options = options || {};
this.directed = (options.directed != null) ? options.directed : true;
this.vertexes = [];
this.edges = []; }
Graph.prototype.vertex = function(name) {
var v = {
adjacent: [],
name: name.toString()
};
this.vertexes.push(v);
return this; };
Graph.prototype.get = function(name) {
return this.vertexes.filter(function(el) {
return el.name === name.toString();
})[0]; };
Graph.prototype.edge = function(a, b, w) {
var that = this;
connect(a, b, w);
if (!this.directed) {
connect(b, a, w);
}
function connect(a, b, data) {
var u = that.vertexes.filter(function(el) {
return el.name === a.toString();
})[0];
var v = that.vertexes.filter(function(el) {
return el.name === b.toString();
})[0];
u.adjacent.push(v);
that.edges.push({
from: u,
to: v,
data: data
});
}
return this; };
function main() {
var g = new Graph();
g.vertex(1)
.vertex(2)
.vertex(3)
.vertex(4)
.vertex(5)
.vertex(6)
.vertex(7)
.vertex(8);
g.edge(1, 2, -2);
g.edge(1, 5, -2);
g.edge(1, 6, -3);
g.edge(1, 8, -1);
g.edge(2, 6, 7);
g.edge(2, 8, 4);
g.edge(3, 2, 2);
g.edge(3, 4, 5);
g.edge(3, 7, 9);
g.edge(4, 7, 4);
g.edge(5, 7, 5);
g.edge(7, 8, -1);
g.edge(8, 2, 2);
g.edge(8, 5, 8);
g.edge(8, 6, 3);
g.edge(8, 7, 7);
shortestPath(g, g.get(3));
console.log(g); }
main();
(Shortest path Bellman-Ford)
and don't really get it why it throws the error property 'length' of undefined in the console.
Any advice how to fix this error?
In general, when JS complains Cannot read property "xxx" of undefined, that means that somewhere you have foo.xxx and foo is the JavaScript value undefined (which is not an object, and has no properties).
Track such a problem down by finding the line in question (using debugging tools, or even just looking for .length in your case) and considering: when might the variable in question be undefined?
In your specific case, the error occurs on this line:
for (var i = 0; i < result[0].length; i++) {
which means that result[0] is undefined. Which means that your result array has no value at [0]. It is empty.
Since the printResult function is called from one place (line 59), this likely means that result is still an empty array when printResult() is called. You can confirm this by setting a breakpoint at that location and examining what result is.
As for why it is empty:
The only code that affects the result array is result.push(a) in the printGraph() function. And this function is never called. Ask your friend why s/he defined printGraph() but never invoked it.
It may be as simple as calling printGraph(g) right before printResult().

javascript, compare arrays of different sizes

with two arrays of potentially different sizes, what is best way to see if they are the same as far as it goes
for example
var a1 = [ 1, 2, 3 ];
var a2 = [ 1, 2 ];
var a3 = [ 1, 3 ];
a1 == a2 => true;
a1 == a3 => false;
am positive this has been done thousands of times and the syntax is well memorized
What about this (I'll just demonstrate on a1 and a2 -> I presume you can make function out of this):
var min_val = min(a1.length, a2.length);
var equals = true;
for(i = 0; i < min_val; i++)
{
if(a1[i] != a2[i])
{
equals = false;
break;
}
}
The result will be in equals variable of course. If you want to make function out of this, just pass a1 and a2 as arguments and return equals.
function compareArraySeq(a, b) {
return a.slice(0, b.length).join(' ') == b.slice(0, a.length).join(' ');
}
function compareArraySeq(a1, a2) {
var i, l = Math.min(a1.length, a2.length);
for (i=0; i<l; i++) {
if (a1[i] !== a2[i]) return false;
}
return true;
}
[edit] based on Tomalaks comments I'd say JSON can come to the rescue.
So, again: here's an Array extension that does what [I suppose] you want to do:
function comparePartial(arr1,arr2){
var arr2 = this, l1 = arr1.length, l2 = arr2.length;
return ( l1<1 || l2<1
? false :
JSON.stringify(arr1.slice(0, l2)) ===
JSON.stringify(arr2.slice(0, l1))
);
}
Array.prototype.comparePartial =
Array.prototype.comparePartial || comparePartial;
//usage
var a1 = [ 1, 2, 3 ]
,a2 = [ 1, 2 ]
,a3 = [ 1, 3 ]
,a4 = ['','']
,a5 = ['','','']
,a6 = []
,a7 = ['bla','doh',1]
,a8 = ['bla','doh',1,'yeah','really']
,a9 = [1,3,5,'doh']
,a10= ['1','3','5','doh']
,a11= [{a:1,b:2},{c:3,d:4}]
,a12= [{a:1,b:2},{c:3,d:4},{e:5,f:6}]
console.log(
[ a1.comparePartial(a2)
,a2.comparePartial(a1)
,a1.comparePartial(a3)
,a4.comparePartial(a5)
,a5.comparePartial(a6)
,a1.comparePartial(a6)
,a8.comparePartial(a7)
,a10.comparePartial(a9) //=> 'type safe' comparison
,a11.comparePartial(a12) //=> can compare arrays of Objects
].join(' - ')
); //=> true - true - false - true - false - false - true - false - true
function prefixEqual(a, b) {
var prefixLength = a.length < b.length ? a.length : b.length;
for(var i = 0; i < prefixLength; i+=1)
if( a[i] != b[i] )
return false;
return true;
}
Make a loop checking one spot at a time.
I have made this:
var compare = function (a1, a2) {
var l = Math.min(a1.length, a2.length);
for (var i = 0; i < l; i++) {
if (a1[i] !== a2[i]) {
return false;
}
}
return true;
}
Now you can compare arrays like this:
var a = [0, 1, 2, 3];
var b = [0, 1, 2];
var c = [0, 1, 3];
compare(a, b); //true
compare(a, c); //false
Hope this works for you :)
Fiddle link: http://jsfiddle.net/8zbJj/1/
If your arrays are strings or numbers or booleans you can compare their String values.
function compareSimpleValues(a,b){
if(a.length>=b.length)return String(a).indexOf(String(b))===0;
return String(b).indexOf(String(a))===0;
}

Categories