JavaScript - String Comparision fails even though both are same - javascript

The following code is failing when I call it with isValid("()"). When I debugged it, I see that the comparision fails at parantheses[parantheses.length - 1] === p even though both the values are same. Can anyone tell why this is failing ?
var isValid = function(s) {
const openParantheses = new Set("(", "{", "[");
const closedParantheses = new Set(")", "}", "]");
const parantheses = [];
for (let p of s) {
if (openParantheses.has(p)) {
parantheses.push(p);
} else if (closedParantheses.has(p)) {
if (parantheses[parantheses.length - 1] === p) {
parantheses.pop();
} else {
return false;
}
}
}
if (parantheses.length > 0) {
return false;
}
return true;
};
console.log(isValid("()"))
Also when I do console.log(Inside If - ${parantheses}) This isnt printing the parantheses array as an array but just giving out values without array notation. Is this something expected ?
Thanks.

Since you never add closed parentheses to the array, the parantheses[parantheses.length - 1] === p clause is never true.
I would advise mapping closed parentheses to open ones and using this map to perform your check as I have done below.
Another thing: The Constructor of Set takes an array (or any iterable) of values. (source)
var isValid = function(testString) {
const openParantheses = new Set([
"(",
"{",
"["
]);
const closedParantheses = new Map([
[')', '('],
[']', '['],
['}', '{'],
]);
const parantheses = [];
for (const character of testString) {
if (openParantheses.has(character)) {
parantheses.push(character);
continue;
}
if (closedParantheses.has(character)) {
if (parantheses[parantheses.length - 1] === closedParantheses.get(character)) {
parantheses.pop();
continue;
}
return false;
}
}
return parantheses.length === 0;
};
console.log(isValid("()"));
console.log(isValid("[]"));
console.log(isValid("{}"));
console.log(isValid("([{}])"));
console.log(isValid("({[}])"));

var isValid = function(s) {
const openParantheses = "({[";
const closedParantheses = ")}]";
const parantheses = [];
for (let p of s) {
if (openParantheses.indexOf(p) >= 0) {
parantheses.push(p);
} else if (closedParantheses.indexOf(p) >= 0) {
if (openParantheses.indexOf(parantheses[parantheses.length - 1]) ===
closedParantheses.indexOf(p)) {
parantheses.pop();
} else {
return false;
}
}
}
if (parantheses.length > 0) {
return false;
}
return true;
};
console.log(isValid("()"))

Related

Counting values of a stack using a javascript algorithm

I need help figuring out how to make a JavaScript algorithm that count the values of a stack, I am given 3 custom methods
stack - a Stack object containing zero or more values.
.pop() which pops the top value of the stack
.push() which pushes a value on to the stack
.peek() which shows me the top value of the stack without modifying the stack
I tried simply returning the length of said stack like so
function countValues(stack) {
return stack.length
}
but i get back undefined thus having no success
this is the stack class that was used to implement the custom methods
class Stack {
constructor(...values) {
const data = {};
let index = 0;
this.push = function (value) {
if (arguments.length < 1) {
throw new TypeError('stack.push() requires a value argument');
}
if (typeof value === 'undefined') {
throw new TypeError('stack.push(value) received undefined');
}
data[index] = value;
index++;
};
this.pop = function () {
const last = index - 1;
if (last < 0) return;
const value = data[last];
delete data[last];
index = last;
return value;
};
this.peek = function () {
const last = index - 1;
if (last < 0) return;
return data[last];
};
this.print = function () {
if (index === 0) {
return 'Stack { <empty> }';
}
let output = ' }';
let last = index - 1;
for (; last > 0; last--) {
output = ' <- ' + JSON.stringify(data[last]) + output;
}
output = JSON.stringify(data[last]) + output;
return 'Stack { ' + output;
};
for (let i = 0; i < values.length; i++) {
this.push(values[i]);
}
Object.freeze(this);
}
}
class Stack {
constructor(...values) {
const data = {};
let index = 0;
this.push = function(value) {
if (arguments.length < 1) {
throw new TypeError('stack.push() requires a value argument');
}
if (typeof value === 'undefined') {
throw new TypeError('stack.push(value) received undefined');
}
data[index] = value;
index++;
};
this.pop = function() {
const last = index - 1;
if (last < 0) return;
const value = data[last];
delete data[last];
index = last;
return value;
};
this.peek = function() {
const last = index - 1;
if (last < 0) return;
return data[last];
};
this.print = function() {
if (index === 0) {
return 'Stack { <empty> }';
}
let output = ' }';
let last = index - 1;
for (; last > 0; last--) {
output = ' <- ' + JSON.stringify(data[last]) + output;
}
output = JSON.stringify(data[last]) + output;
return 'Stack { ' + output;
};
for (let i = 0; i < values.length; i++) {
this.push(values[i]);
}
Object.freeze(this);
}
}
const myStack = new Stack(1, 2, 3, 4, 5);
// Here's an easy but not so good way:
function countValues1(stack) {
return Array.from(stack.print()).filter(x => x === "<").length + 1;
}
// Here's another way, but it mutates the stack:
function countValues2(stack) {
let count = 0;
while (true) {
if (stack.pop() === undefined) {
break;
}
count++;
}
return count;
}
console.log(countValues1(myStack));
console.log(countValues2(myStack));
Without knowing exactly how stack works, or specifically what you need (are you allowed to modify the stack implementation? are you allowed to mutate the contents of the stack?) we'll struggle for a good answer, but the above should help get you maybe slightly closer perhaps.
Maybe this can help you doing a length function manually.
You should check how you declared your stack, .length is supposed to be working.
function countValues(stack) {
const tempStack = stack;
var length=0;
while(tempStack.pop()!=undefined){
length++;
}
return length;
}
This function allows you to run it and still keeping your data in the original stack.
length is a getter, which is essentially a function posing as a property. It will just return undefined if you call it on an object that doesn't implement it. If the exercise -- I assume that's what it is -- says you can only use the abovementioned methods, then you can't use object.length.

Return true if the string in the first element of the array contains all of the letters of the string in the second element

I tried to do this by resetting loop going trough firstword every time its letter matches with secondword letter.
function mutation(arr) {
var compare = [];
var firstword = arr[0].toLowerCase();
var secondword = arr[1].toLowerCase();
var j = 0;
for (let i = 0; i < firstword.length; i++) {
if (firstword[i] === secondword[j]) {
compare.push(secondword[i]);
i = -1;
j++;
}
}
let result = compare.join("")
if (result.length === secondword.length) {
return true;
} else {
return false;
}
}
console.log(mutation(["Noel", "Ole"]));
It works in some cases but in others, like above example, it doesn't. What seems to be the problem?
You need to compare.push(secondword[j]) instead of compare.push(secondword[i])
function mutation(arr) {
var compare = [];
var firstword = arr[0].toLowerCase();
var secondword = arr[1].toLowerCase();
var j = 0;
for (let i = 0; i < firstword.length; i++) {
if (firstword[i] === secondword[j]) {
compare.push(secondword[j]); // Correction here
i = -1;
j++;
}
}
let result = compare.join("");
if (result.length === secondword.length) {
return true;
} else {
return false;
}
}
console.log(mutation(["Noel", "Ole"]));
Also, you can consider using Array.prototype.every.
const mutation = ([first, sec]) => {
const lowerCaseFirst = first.toLowerCase();
const lowerCaseSec = sec.toLowerCase();
return Array.from(lowerCaseSec).every((ch) => lowerCaseFirst.includes(ch));
};
console.log(mutation(["Noel", "Ole"]));
If the strings are small then String.prototype.includes works fine but if they are large then you should consider using a Set.
const mutation = ([first, sec]) => {
const firstSet = new Set(first.toLowerCase());
const lowerCaseSec = sec.toLowerCase();
return Array.from(lowerCaseSec).every((ch) => firstSet.has(ch));
};
console.log(mutation(["Noel", "Ole"]));
Simple ES6 Function, we check with .every() if every characters of secondword is includes inside firstword. It return true if it does.
function mutation(arr) {
const firstword = arr[0].toLowerCase();
const secondword = arr[1].toLowerCase();
return secondword.split('').every(char => firstword.includes(char));
}
console.log(mutation(["Noel", "Ole"]));
The use of Set in SSM's answer works if you don't need to account for duplicate characters in the second string. If you do, here's an implementation that uses a Map of character counts. The map key is the character from string 1 and the value is the number of occurrences. For instance, if you want ["Noel", "Ole"] to return true, but ["Noel", "Olle"] to return false (string 1 does not contain 2 "l" characters). String 2 is then iterated through and character counts decremented if they exist. As soon as a character is not present or the count falls below 1 in the map, the function returns false.
function mutation(arr: string[]): boolean {
return s1ContainsAllCharsInS2(arr[0].toLowerCase(), arr[1].toLowerCase());
}
function s1ContainsAllCharsInS2(s1: string, s2: string): boolean {
if (s2.length > s1.length) {
return false;
}
let charCountMap: Map<string, number> = new Map<string, number>();
Array.from(s1).forEach(c => {
let currentCharCount: number = charCountMap.get(c);
charCountMap.set(c, 1 + (currentCharCount ? currentCharCount : 0));
});
return !Array.from(s2).some(c => {
let currentCharCount: number = charCountMap.get(c);
if (!currentCharCount || currentCharCount < 1){
return true;
}
charCountMap.set(c, currentCharCount - 1);
});
}
A different approach.
Mapping the characters and comparing against that map.
function mutation(arr) {
const chars = {};
for (let char of arr[0].toLowerCase()) {
chars[char] = true;
}
for (let char of arr[1].toLowerCase()) {
if (!chars[char]) {
return false;
}
}
return true;
}
console.log(mutation(["Noel", "Ole"]));
console.log(mutation(["Noel", "Oleeeeeeeeeeeee"]));
If the count also matters (your code doesn't take it into account) you can count the number of occurrences of each character and comparing these counts.
function mutation(arr) {
const chars = {};
for (let char of arr[0].toLowerCase()) {
chars[char] = (chars[char] || 0) + 1;
}
for (let char of arr[1].toLowerCase()) {
// check if chars[char] contains a (not empty == positive) count
// then decrement it for future checks
if (!chars[char]--) {
return false;
}
}
return true;
}
console.log(mutation(["Noel", "Ole"]));
console.log(mutation(["Noel", "Oleeeeeeeeeeeee"]));

JavaScript Return isn't returning

I wrote a simple function checking if an array contains duplicates, I want it to return true if it does and false if it doesn't.
function containsDuplicates(a) {
var hash = {};
a.forEach((elem, index) => {
if (hash[elem] === undefined) {
hash[elem] = 1;
} else {
console.log('true')
return true;
}
if (index === a.length - 1) {
console.log('false')
return false;
}
})
}
var arr = [1, 2, 3, 4];
containsDuplicates(arr)
My console.log logs just fine but it doesn't seem to be hitting the return. My entire function returns undefined every time. Why is this the case?
You are returning from the callback that you passed to forEach().
You are returning from the callback you passed to foreach. You should try something like this instead.
function hasDuplicates(array) {
var keyStore = {};
for (var i = 0; i < array.length; ++i) {
var value = array[i];
if (value in keyStore) {
return true;
}
keyStore[value] = true;
}
return false;
}

Checking if the characters in a string are all unique

I am trying to solve this problem using JS by just using an array.
var str = 'abcdefgh';
for (i = 0; i < 255; i++) {
arr[i] = false;
}
function check() {
for (i = 0; i < str.length; i++) {
if (arr[str.charCodeAt(i)] == true) {
return false;
}
arr[str.charCodeAt(i)] = true;
}
return true;
}
I am initializing an array of fixed size 256 to have the boolean value false.
Then i am setting the value for the corresponding ASCII index to true for characters in the string. And if i find the same character again, i am returning false.
While running the program, i am getting false returned even if the string doesn't have any duplicate characters.
Fill a Set with all characters and compare its size to the string's length:
function isUnique(str) {
return new Set(str).size == str.length;
}
console.log(isUnique('abc')); // true
console.log(isUnique('abcabc')); // false
Use object for faster result
function is_unique(str) {
var obj = {};
for (var z = 0; z < str.length; ++z) {
var ch = str[z];
if (obj[ch]) return false;
obj[ch] = true;
}
return true;
}
console.log(is_unique("abcdefgh")); // true
console.log(is_unique("aa")); // false
use .match() function for each of the character. calculate occurrences using length. Guess thats it.
(str.match(/yourChar/g) || []).length
We can also try using indexOf and lastIndexOf method:
function stringIsUnique(input) {
for (i = 0; i < input.length; i++) {
if (input.indexOf(input[i]) !== input.lastIndexOf(input[i])) {
return false;
}
}
return true;
}
You are using arr[str.charCodeAt(i)] which is wrong.
It should be arr[str[i].charCodeAt(0)]
var arr = [];
var str="abcdefgh";
for (i=0;i<255;i++){
arr[i]=false;
}
function check(){
for (i=0;i<str.length;i++){
if (arr[str[i].charCodeAt(0)]==true){
return false;
}
arr[str[i].charCodeAt(0)]=true;
}
console.log(arr);
return true;
}
check();
Time complexity = O(n)
Space complexity = O(n)
const isUnique = (str) => {
let charCount = {};
for(let i = 0; i < str.length; i++) {
if(charCount[str[i]]){
return false;
}
charCount[str[i]] = true;
}
return true;
}
const isUniqueCheekyVersion = (str) => {
return new Set(str).size === str.length;
}
Solution 3:
Transform string to chars array, sort them and then loop through them to check the adjacent elements, if there is a match return false else true
Solution 4:
It's similar to Solution 1 except that we use a Set data structure which is introduced in recent versions of javascript
// no additional Data structure is required. we can use naive solution
// Time Complexity:O(n^2)
function isUnique(str) {
for (let i = 0; i < str.length; i++) {
for (let j = 1 + i; j < str.length; j++) {
if (str[i] === str[j]) {
return false;
}
}
}
return true;
}
// if you can use additional Data structure
// Time Complexity:O(n)
function isUniqueSecondMethos(str) {
let dup_str = new Set();
for (let i = 0; i < str.length; i++) {
if (dup_str.has(str[i])) {
return false;
}
dup_str.add(str[i]);
}
return true;
}
console.log(isUniqueSecondMethos('hello'));
Use an object as a mapper
function uniqueCharacterString(inputString) {
const characterMap = {};
let areCharactersUnique = true;
inputString.trim().split("").map((ch)=>{
if(characterMap[ch]===undefined) {
characterMap[ch] = 1;
} else {
areCharactersUnique = false;
}
})
return areCharactersUnique;
}
Algo
*1. step -first string is ->stack *
*2.step-string covert to CharArray *
3. step - use iteration in array ['s','t','a','c','k']
4. step - if(beginElement !== nextElement){return true}else{return false}
Implement code
function uniqueChars(string){
var charArray = Array.from(string) //convert charArray
for(var i=0;i<charArray.length;i++){
if(charArray[i] !== charArray[i+1]){
return true
}
else{
return false
}
}
}
var string ="stack"
console.log(uniqueChars(string))
Time complexity
O(nlogn)
Algo
Counting frequency of alphabets. e.g. 'Mozilla' will returns Object{ M: 1, o: 1, z: 1, i: 1, l: 2, a: 1 }. Note that, the bitwise NOT operator (~) on -~undefined is 1, -~1 is 2, -~2 is 3 etc.
Return true when all occurrences appear only once.
Implement code
var isUnique = (str) => {
const hash = {};
for (const key of str) {
hash[key] = -~hash[key];
}
return Object.values(hash).every((t) => t === 1);
};
console.log(isUnique('Mozilla'));
console.log(isUnique('Firefox'));
Another alternative could be:
var isUnique = (str) => {
const hash = {};
for (const i in str) {
if (hash[str[i]]) return false;
hash[str[i]] = true;
}
return true;
};
console.log(isUnique('Mozilla'));
console.log(isUnique('Firefox'));
To make efficient one, you can use simple hash map
let isUnique = (s) => {
let ar = [...s];
let check = {};
for (let a of ar) {
if (!check[a]) {
check[a] = 1;
} else {
return false
}
}
return true;
}
alert("isUnique : "+isUnique("kailu"));
Time complexity & Space complexity
using ES6
let isUnique = (s)=>{
return new Set([...s]).size == s.length;
}
console.log("using ES6 : ",isUnique("kailu"));
We can use split method of string:
const checkString = (str) => {
let isUniq = true;
for (let i = 0; i < str.length; i++) {
if (str.split(str[i]).length > 2) {
isUniq = false;
break;
}
}
return isUniq;
};
console.log(checkString("abcdefgh")); //true
console.log(checkString("aa")); //false

JavaScript anagram comparison

I'm trying to compare two strings to see if they are anagrams.
My problem is that I'm only comparing the first letter in each string. For example, "Mary" and "Army" will return true but unfortunately so will "Mary" and Arms."
How can I compare each letter of both strings before returning true/false?
Here's a jsbin demo (click the "Console" tab to see the results"):
http://jsbin.com/hasofodi/1/edit
function compare (a, b) {
y = a.split("").sort();
z = b.split("").sort();
for (i=0; i<y.length; i++) {
if(y.length===z.length) {
if (y[i]===z[i]){
console.log(a + " and " + b + " are anagrams!");
break;
}
else {
console.log(a + " and " + b + " are not anagrams.");
break;
}
}
else {
console.log(a + " has a different amount of letters than " + b);
}
break;
}
}
compare("mary", "arms");
Instead of comparing letter by letter, after sorting you can join the arrays to strings again, and let the browser do the comparison:
function compare (a, b) {
var y = a.split("").sort().join(""),
z = b.split("").sort().join("");
console.log(z === y
? a + " and " + b + " are anagrams!"
: a + " and " + b + " are not anagrams."
);
}
If you want to write a function, without using inbuilt one, Check the below solution.
function isAnagram(str1, str2) {
if(str1 === str2) {
return true;
}
let srt1Length = str1.length;
let srt2Length = str2.length;
if(srt1Length !== srt2Length) {
return false;
}
var counts = {};
for(let i = 0; i < srt1Length; i++) {
let index = str1.charCodeAt(i)-97;
counts[index] = (counts[index] || 0) + 1;
}
for(let j = 0; j < srt2Length; j++) {
let index = str2.charCodeAt(j)-97;
if (!counts[index]) {
return false;
}
counts[index]--;
}
return true;
}
This considers case sensitivity and removes white spaces AND ignore all non-alphanumeric characters
function compare(a,b) {
var c = a.replace(/\W+/g, '').toLowerCase().split("").sort().join("");
var d = b.replace(/\W+/g, '').toLowerCase().split("").sort().join("");
return (c ===d) ? "Anagram":"Not anagram";
}
Quick one-liner solution with javascript functions - toLowerCase(), split(), sort() and join():
Convert input string to lowercase
Make array of the string with split()
Sort the array alphabetically
Now join the sorted array into a string using join()
Do the above steps to both strings and if after sorting strings are the same then it will be anargam.
// Return true if two strings are anagram else return false
function Compare(str1, str2){
if (str1.length !== str2.length) {
return false
}
return str1.toLowerCase().split("").sort().join("") === str2.toLowerCase().split("").sort().join("")
}
console.log(Compare("Listen", "Silent")) //true
console.log(Compare("Mary", "arms")) //false
No need for sorting, splitting, or joining. The following two options are efficient ways to go:
//using char array for fast lookups
const Anagrams1 = (str1 = '', str2 = '') => {
if (str1.length !== str2.length) {
return false;
}
if (str1 === str2) {
return true;
}
const charCount = [];
let startIndex = str1.charCodeAt(0);
for (let i = 0; i < str1.length; i++) {
const charInt1 = str1.charCodeAt(i);
const charInt2 = str2.charCodeAt(i);
startIndex = Math.min(charInt1, charInt2);
charCount[charInt1] = (charCount[charInt1] || 0) + 1;
charCount[charInt2] = (charCount[charInt2] || 0) - 1;
}
while (charCount.length >= startIndex) {
if (charCount.pop()) {
return false;
}
}
return true;
}
console.log(Anagrams1('afc','acf'))//true
console.log(Anagrams1('baaa','bbaa'))//false
console.log(Anagrams1('banana','bananas'))//false
console.log(Anagrams1('',' '))//false
console.log(Anagrams1(9,'hey'))//false
//using {} for fast lookups
function Anagrams(str1 = '', str2 = '') {
if (str1.length !== str2.length) {
return false;
}
if (str1 === str2) {
return true;
}
const lookup = {};
for (let i = 0; i < str1.length; i++) {
const char1 = str1[i];
const char2 = str2[i];
const remainingChars = str1.length - (i + 1);
lookup[char1] = (lookup[char1] || 0) + 1;
lookup[char2] = (lookup[char2] || 0) - 1;
if (lookup[char1] > remainingChars || lookup[char2] > remainingChars) {
return false;
}
}
for (let i = 0; i < str1.length; i++) {
if (lookup[str1[i]] !== 0 || lookup[str2[i]] !== 0) {
return false;
}
}
return true;
}
console.log(Anagrams('abc', 'cba'));//true
console.log(Anagrams('abcc', 'cbaa')); //false
console.log(Anagrams('abc', 'cde')); //false
console.log(Anagrams('aaaaaaaabbbbbb','bbbbbbbbbaaaaa'));//false
console.log(Anagrams('banana', 'ananab'));//true
Cleanest and most efficient solution for me
function compare(word1, word2) {
const { length } = word1
if (length !== word2.length) {
return false
}
const charCounts = {}
for (let i = 0; i < length; i++) {
const char1 = word1[i]
const char2 = word2[i]
charCounts[char1] = (charCounts[char1] || 0) + 1
charCounts[char2] = (charCounts[char2] || 0) - 1
}
for (const char in charCounts) {
if (charCounts[char]) {
return false
}
}
return true
}
I modified your function to work.
It will loop through each letter of both words UNTIL a letter doesn't match (then it knows that they AREN'T anagrams).
It will only work for words that have the same number of letters and that are perfect anagrams.
function compare (a, b) {
y = a.split("").sort();
z = b.split("").sort();
areAnagrams = true;
for (i=0; i<y.length && areAnagrams; i++) {
console.log(i);
if(y.length===z.length) {
if (y[i]===z[i]){
// good for now
console.log('up to now it matches');
} else {
// a letter differs
console.log('a letter differs');
areAnagrams = false;
}
}
else {
console.log(a + " has a different amount of letters than " + b);
areAnagrams = false;
}
}
if (areAnagrams) {
console.log('They ARE anagrams');
} else {
console.log('They are NOT anagrams');
}
return areAnagrams;
}
compare("mary", "arms");
A more modern solution without sorting.
function(s, t) {
if(s === t) return true
if(s.length !== t.length) return false
let count = {}
for(let letter of s)
count[letter] = (count[letter] || 0) + 1
for(let letter of t) {
if(!count[letter]) return false
else --count[letter]
}
return true;
}
function validAnagramOrNot(a, b) {
if (a.length !== b.length)
return false;
const lookup = {};
for (let i = 0; i < a.length; i++) {
let character = a[i];
lookup[character] = (lookup[character] || 0) + 1;
}
for (let i = 0; i < b.length; i++) {
let character = b[i];
if (!lookup[character]) {
return false;
} else {
lookup[character]--;
}
}
return true;
}
validAnagramOrNot("a", "b"); // false
validAnagramOrNot("aza", "zaa"); //true
Here's my contribution, I had to do this exercise for a class! I'm finally understanding how JS works, and as I was able to came up with a solution (it's not - by far - the best one, but it's ok!) I'm very happy I can share this one here, too! (although there are plenty solutions here already, but whatever :P )
function isAnagram(string1, string2) {
// first check: if the lenghts are different, not an anagram
if (string1.length != string2.length)
return false
else {
// it doesn't matter if the letters are capitalized,
// so the toLowerCase method ensures that...
string1 = string1.toLowerCase()
string2 = string2.toLowerCase()
// for each letter in the string (I could've used for each :P)
for (let i = 0; i < string1.length; i++) {
// check, for each char in string2, if they are NOT somewhere at string1
if (!string1.includes(string2.charAt(i))) {
return false
}
else {
// if all the chars are covered
// and the condition is the opposite of the previous if
if (i == (string1.length - 1))
return true
}
}
}
}
First of all, you can do the length check before the for loop, no need to do it for each character...
Also, "break" breaks the whole for loop. If you use "continue" instead of "break", it skips the current step.
That is why only the first letters are compared, after the first one it quits the for loop.
I hope this helps you.
function compare (a, b) {
y = a.split("").sort();
z = b.split("").sort();
if(y.length==z.length) {
for (i=0; i<y.length; i++) {
if (y[i]!==z[i]){
console.log(a + " and " + b + " are not anagrams!");
return false;
}
}
return true;
} else { return false;}}
compare("mary", "arms");
Make the function return false if the length between words differ and if it finds a character between the words that doesn't match.
// check if two strings are anagrams
var areAnagrams = function(a, b) {
// if length is not the same the words can't be anagrams
if (a.length != b.length) return false;
// make words comparable
a = a.split("").sort().join("");
b = b.split("").sort().join("");
// check if each character match before proceeding
for (var i = 0; i < a.length; i++) {
if ((a.charAt(i)) != (b.charAt(i))) {
return false;
}
}
// all characters match!
return true;
};
It is specially effective when one is iterating through a big dictionary array, as it compares the first letter of each "normalised" word before proceeding to compare the second letter - and so on. If one letter doesn't match, it jumps to the next word, saving a lot of time.
In a dictionary with 1140 words (not all anagrams), the whole check was done 70% faster than if using the method in the currently accepted answer.
an anagram with modern javascript that can be use in nodejs. This will take into consideration empty strings, whitespace and case-sensitivity. Basically takes an array or a single string as input. It relies on sorting the input string and then looping over the list of words and doing the same and then comparing the strings to each other. It's very efficient. A more efficient solution may be to create a trie data structure and then traversing each string in the list. looping over the two words to compare strings is slower than using the built-in string equality check.
The function does not allow the same word as the input to be considered an anagram, as it is not an anagram. ;) useful edge-case.
const input = 'alerting';
const list1 = 'triangle';
const list2 = ['', ' ', 'alerting', 'buster', 'integral', 'relating', 'no', 'fellas', 'triangle', 'chucking'];
const isAnagram = ((input, list) => {
if (typeof list === 'string') {
list = [list];
}
const anagrams = [];
const sortedInput = sortWord(input).toLowerCase();
const inputLength = sortedInput.length;
list.forEach((element, i) => {
if ( inputLength === element.length && input !== element ) {
const sortedElement = sortWord(element).toLowerCase();
if ( sortedInput === sortedElement) {
anagrams.push(element);
}
}
});
return anagrams;
})
const sortWord = ((word) => {
return word.split('').sort().join('');
});
console.log(`anagrams for ${input} are: ${isAnagram(input, list1)}.`);
console.log(`anagrams for ${input} are: ${isAnagram(input, list2)}.`);
Here is a simple algorithm:
1. Remove all unnecessary characters
2. make objects of each character
3. check to see if object length matches and character count matches - then return true
const stripChar = (str) =>
{
return str.replace(/[\W]/g,'').toLowerCase();
}
const charMap = str => {
let MAP = {};
for (let char of stripChar(str)) {
!MAP[char] ? (MAP[char] = 1) : MAP[char]++;
}
return MAP;
};
const anagram = (str1, str2) => {
if(Object.keys(charMap(str1)).length!==Object.keys(charMap(str2)).length) return false;
for(let char in charMap(str1))
{
if(charMap(str1)[char]!==charMap(str2)[char]) return false;
}
return true;
};
console.log(anagram("rail safety","!f%airy tales"));
I think this is quite easy and simple.
function checkAnagrams(str1, str2){
var newstr1 = str1.toLowerCase().split('').sort().join();
var newstr2 = str2.toLowerCase().split('').sort().join();
if(newstr1 == newstr2){
console.log("String is Anagrams");
}
else{
console.log("String is Not Anagrams");
}
}
checkAnagrams("Hello", "lolHe");
checkAnagrams("Indian", "nIndisn");
//The best code so far that checks, white space, non alphabets
//characters
//without sorting
function anagram(stringOne,stringTwo){
var newStringOne = ""
var newStringTwo = ''
for(var i=0; i<stringTwo.length; i++){
if(stringTwo[i]!= ' ' && isNaN(stringTwo[i]) == true){
newStringTwo = newStringTwo+stringTwo[i]
}
}
for(var i=0; i<stringOne.length; i++){
if(newStringTwo.toLowerCase().includes(stringOne[i].toLowerCase())){
newStringOne=newStringOne+stringOne[i].toLowerCase()
}
}
console.log(newStringOne.length, newStringTwo.length)
if(newStringOne.length==newStringTwo.length){
console.log("Anagram is === to TRUE")
}
else{console.log("Anagram is === to FALSE")}
}
anagram('ddffTTh####$', '#dfT9t#D##H$F')
function anagrams(str1,str2){
//spliting string into array
let arr1 = str1.split("");
let arr2 = str2.split("");
//verifying array lengths
if(arr1.length !== arr2.length){
return false;
}
//creating objects
let frqcounter1={};
let frqcounter2 ={};
// looping through array elements and keeping count
for(let val of arr1){
frqcounter1[val] =(frqcounter1[val] || 0) + 1;
}
for(let val of arr2){
frqcounter2[val] =(frqcounter2[val] || 0) + 1;
}
console.log(frqcounter1);
console.log(frqcounter2);
//loop for every key in first object
for(let key in frqcounter1){
//if second object does not contain same frq count
if(frqcounter2[key] !== frqcounter1[key]){
return false;
}
}
return true;
}
anagrams('anagrams','nagramas');
The fastest Algorithm
const isAnagram = (str1, str2) => {
if (str1.length !== str2.length) {
return false
}
const obj = {}
for (let i = 0; i < str1.length; i++) {
const letter = str1[i]
obj[letter] ? obj[letter] += 1 : obj[letter] = 1
}
for (let i = 0; i < str2.length; i++) {
const letter = str2[i]
if (!obj[letter]) {
return false
}
else {
obj[letter] -= 1
}
}
return true
}
console.log(isAnagram('lalalalalalalalala', 'laalallalalalalala'))
console.time('1')
isAnagram('lalalalalalalalala', 'laalallalalalalala') // about 0.050ms
console.timeEnd('1')
const anagram = (strA, strB) => {
const buildAnagram = (str) => {
const charObj = {};
for(let char of str.replace(/[^\w]/g).toLowerCase()) {
charObj[char] = charObj[char] + 1 || 1;
}
return charObj;
};
const strObjAnagramA = buildAnagram(strA);
const strObjAnagramB = buildAnagram(strB);
if(Object.keys(strObjAnagramA).length !== Object.keys(strObjAnagramB).length) {
console.log(strA + ' and ' + strB + ' is not an anagram');
return false;
}
for(let char in strObjAnagramA) {
if(strObjAnagramA[char] !== strObjAnagramB[char]) {
console.log(strA + ' and ' + strB + ' is not an anagram');
return false;
}
}
return true; } //console.log(anagram('Mary','Arms')); - false
Similar approach with filter function
const str1 = 'triangde'
const str2 = 'integral'
const st1 = str1.split('')
const st2 = str2.split('')
const item = st1.filter((v)=>!st2.includes(v))
const result = item.length === 0 ? 'Anagram' : 'Not anagram' + ' Difference - ' + item;
console.log(result)

Categories

Resources