My code is not comparing two different strings correctly - javascript

I am attempting to solve this codewars problem:
Complete the function scramble(str1, str2) that returns true if a
portion of str1 characters can be rearranged to match str2, otherwise
returns false.
examples:
scramble('rkqodlw', 'world') ==> True
scramble('cedewaraaossoqqyt', 'codewars') ==> True
scramble('katas', 'steak') ==> False
This is my attempt:
function scramble(str1, str2) {
let obj1 = {};
let obj2 = {};
for (el of str1) {
obj1[el] = (obj1[el] || 0) + 1;
}
for (el of str2) {
obj2[el] = (obj2[el] || 0) + 1;
}
for (el in obj2) {
if (!(el in obj1)) return false;
}
return true;
}
I am converting the strings to objects, and then comparing the keys to each other. My code passes about 90% of all the tests on Codewars, but then it does not pass the other 10% and they do not show what the test inputs are unfortunately.
My hunch is that there are a few edge cases that this code is not catching. Any help would be appreciated.

You will need to handle the case when str2 has more instances of a letter than str1.
For example:
scramble("a", "aa")
Which should evaluate to false (not enough 'a's in "a" to form "aa").

You need to handle the amount of characters. Now you just checking whether the character in str2 also exists in str1.
So instead of:
for (el in obj2) {
if (!(el in obj1)) return false;
}
Try:
for (let [key, value] of Object.entries(obj2)) {
if (obj1[key] === undefined || obj1[key] < value) return false;
}
Which means that if obj1[key] doesn't exist or it has less occurrences than obj2[key] it will return false.

this code maybe helps
function scramble(str1, str2) {
let occurences = str1.split("").reduce((arr, cur) => { arr[cur] ? arr[cur]++ : arr[cur] = 1; return arr; }, {});
console.log(occurences);
return str2.split("").every((character) => --occurences[character] >= 0);
}
console.log(scramble("awpoirwled", "world"));

The algorithm I would use is to take each letter of the match string, and if its got an equivalent in the searched string, remove it from there and continue, otherwise abort if there is no match.
If you reach the end of the match string without aborting then you have a match

Related

Check if a string is made up of multiple occurences of a substring

(JavaScript)
So, I need a function checkString(str, substr) that checks whether a string is made out of multiple occurences of a given substring.
Examples:
checkString("abc", "abc") -> true
checkString("abcabcabc", "abc") -> true
checkString("abcdef", "abc") -> false
checkString("abcab", "abc) -> true
Could someone help me out?
If whitespaces don't matter, this is a solution:
const checkString = (bigString, subString) => {
const split = bigString.split(subString);
const onlyOccurances = split.filter(v => v === '');
return split.length === onlyOccurances.length
}
checkString("abc", "abc") // true
checkString("abcabcabc", "abc") // true
checkString("abcdef", "abc") // false
bigString.split(subString) will split the big string into an array of empty strings if there's perfect match, and the length of it will be exactly how many occurances there are. If any of the values in the array are not empty strings, it means there is not a perfect match so there will be a difference between the length of the filtered by empty and the length of the splited values.
Hope it makes sense.
This method will return an object and found will be true if the value is found in the string and multipleFound will be true if found more than once;
const checkString = function(str, v) {
let found = false,
multi = false,
index;
index = str.indexOf(v);
if (index !== -1) {
found = true;
index = str.indexOf(v, index + v.length);
if (index !== -1) {
multi = true;
}
}
return {
found : found,
multipleFound : multi
};
};
This would be one way to check against the pattern abc:
const rx=/^(abc)+$/;
console.log(["abc","abcabcabc","abcdef"].map(t=>
`${t} ${rx.test(t)}`))

Why does javascript 'if statements' return undefined?

This is more of a 'why does this happen' question than a trouble shooting question.
I am trying to create a function that tests whether a word is a palindrome. I thought initially that I can use an if statement it compare the word and when it is reversed. However the if statement gave me undefined. When I compared it regularly (word === reverseWord), it came back with a truth or false. My question is what is going on in the if statement for it do wonk out? Thanks!
const palindromes = function(word) {
*//Turn word into an array*
var arrWord = Array.from(word);
*//Reverse the array*
var reversedWord = arrWord.reverse();
*//This is true*
return arrWord === reversedWord;
//But this is undefined?
if (arrWord === reversedWord) {true} else {false};
}
Its returning undefined because you are not using return keyword anywhere.
Another mistake you are making is that you are comparing two arrays which reference same object in memory it arrWord === reversedWord will always return true.
Convert word to array using split('') and reverse() it. And then join(''). And finally compare reversed string and word
const palindromes = function(word) {
var reversedWord = word.split('').reverse().join('');
console.log(word === reversedWord);
if (word === reversedWord) {
return true
} else {
return false
};
}
console.log(palindromes("aba"))
console.log(palindromes("ba"))
The code can be reduced to a single line.
const palindromes = (word) => word.split('').reverse().join('') === word
console.log(palindromes("aba"))
console.log(palindromes("ba"))

Anagram solution using json.stringify, is this a right approach to solve

I have sorted out two string and than used json.stringify to compare it to get Anagram. please refer below code, is this a right way to code.
function same(ar, ar1) {
//sorting the string
var o = ar.split("").sort();
var o1 = ar1.split("").sort();
//comparing two string
if (JSON.stringify(o) == JSON.stringify(o1)) {
return true;
} else {
return false;
}
}
same("ria", "air"); //true
same("", ""); //true
same("aaz", zza); //false
It'll work in most cases, but it's unnecessarily computationally expensive.
It may not work when certain non-ASCII characters are used, because .split('') will result in splitting up the character code points, eg:
console.log('𝟘'.split(''));
That's not an accurate representation of each character as an element of the array. Use Array.from instead:
console.log(Array.from('𝟘'));
After that, you can also make the algorithm less expensive by counting up the number of occurrences of each character (O(n)) rather than sorting (O(n log n)). For example:
const getCount = str => Array.from(str).reduce((counts, char) => {
counts[char] = (counts[char] || 0) + 1;
return counts;
}, {});
function same(ar,ar1){
const counts1 = getCount(ar);
const counts2 = getCount(ar1);
const keys1 = Object.keys(counts1);
const keys2 = Object.keys(counts2);
if (keys1.length !== keys2.length) {
return false;
}
return keys1.every(char => counts1[char] === counts2[char]);
}
console.log(same('abc', 'cba'));
console.log(same('abc', 'aba'));

Match pattern in string

I think the issue is that whatever value I have it will always end up being true. If someone could help explain it to me with simple JavaScript for a beginner
function match(string, pattern) {
var i;
var letterFound = true;
var str = string.length;
if (string.indexOf(pattern) != -1)
{
letterFound = true;
} else letterFound = false;
return letterFound;
}
alert(match("abcdef", "#C2D!"));
alert(match("abcdef", "CAfe"));
alert(match("abcdef", "CG"));
Instead of looping through each character, you can use:
string.indexOf(pattern);
Which checks if string contains pattern in one go.
Delete all chars that are not letters with replace(/[^[A-Za-z]]/g, "")
Make array with String.prototype.split()
Go through the array with Array.prototype.map()
Check if every letter (case insensitive) is in the string with String.prototype.includes(). Return bools.
If every bool is true, return true, else return false. ( Array.prototype.every() )
function match(string, pattern) {
return pattern.replace(/[^A-Za-z]/g, "").split("").map(ch => {
return string.includes(ch.toLowerCase());
}).every(bool => bool === true) ? true : false;
}
console.log(match("abcdef", "#C2D!"));
console.log(match("abcdef", "CAfe"));
console.log(match("abcdef", "CG"));

How to check if a string only contains chars from an array?

I try to check if a word (wordToCheck) only consists of letters from an array (letters) and also contains every letter in the array only as often (or rather not more times than they are in the array) as it actually is inside of the array.
Here are examples of what the desired function should return:
checkIfWordContainsLetters("google", ["a","o","o","g","g","l","e","x"]) === true
checkIfWordContainsLetters("google", ["a","o","g","g","l","e","x"]) === false
How can I make this code work?
function checkIfWordContainsLetters(wordToCheck, letters) {
var lettersToString = letters.toString();
var lettersTrimmed = lettersToString.replace(/,/gi, "?");
var regEx = new RegExp(lettersTrimmed, "gi");
if (wordToCheck.match(regEx)!== null) {
return true;
}
else return false;
}
You could use this ES6 function:
function checkIfWordContainsLetters(wordToCheck, letters){
return !letters.reduce((a, b) => a.replace(b,''), wordToCheck.toLowerCase()).length;
}
console.log(checkIfWordContainsLetters("google", ["a","o","o","g","g","l","e","x"]));
console.log(checkIfWordContainsLetters("google", ["a","o","g","g","l","e","x"]));
The idea is to go through each letter in the letters array, and remove one (not more!) occurrence of it in the given wordToCheck argument (well, not exactly in it, but taking a copy that lacks that one character). If after making these removals there are still characters left over, the return value is false -- true otherwise.
Of course, if you use Internet Explorer, you won't have the necessary ES6 support. This is the ES5-compatible code:
function checkIfWordContainsLetters(wordToCheck, letters){
return !letters.reduce(function (a, b) {
return a.replace(b, '');
}, wordToCheck.toLowerCase()).length;
}
console.log(checkIfWordContainsLetters("google", ["a","o","o","g","g","l","e","x"]));
console.log(checkIfWordContainsLetters("google", ["a","o","g","g","l","e","x"]));
As long as it is not the best solution for long strings for which using some clever regex is definitely better, it works for short ones without whitespaces.
function checkIfWordContainsLetters(word, letters){
word = word.toLowerCase().split('');
for(var i = 0; i < letters.length; i++) {
var index = word.indexOf( letters[i].toLowerCase() );
if( index !== -1 ) {
// if word contains that letter, remove it
word.splice( index , 1 );
// if words length is 0, return true
if( !word.length ) return true;
}
}
return false;
}
checkIfWordContainsLetters("google", ["a","o","o","g","g","l","e","x"]); // returns true
checkIfWordContainsLetters("google", ["a","o","g","g","l","e","x"]); // returns false

Categories