How to check if two strings contain same characters in Javascript? - javascript

I have two strings:
var a = 'ABCD';
var b = 'DEFG';
I need to compare these variables to check if there is not a common CHARACTER in the two strings.
So for this case return false (or do something...) because D is a common character in them.

You could merge the two strings then sort it then loop through it and if you find a match you could then exit out the loop.
I found this suggestion on a different stack overflow conversation:
var str="paraven4sr";
var hasDuplicates = (/([a-zA-Z]).*?\1/).test(str)
So if you merge the strings together, you can do the above to use a regexp, instead of looping.

Thank you every one. I tried your solutions, and finally got this :
Merging my two strings into one
to Lower Case,
Sort,
and Join,
using Regex Match if the Final Concatenated string contains any
repetitions,
Return 0 if no Repeat occur or count of repeats.
var a; var b;
var concatStr=a+b;
checkReptCharc=checkRepeatChrcInString(concatStr);
function checkRepeatChrcInString(str){
console.log('Concatenated String rec:' + str);
try{ return
str.toLowerCase().split("").sort().join("").match(/(.)\1+/g).length; }
catch(e){ return 0; }
}

I was also searching for solution to this problem, but came up with this:
a.split('').filter(a_ => b.includes(a_)).length === 0
Split a into array of chars, then use filter to check whether each char in a occurs in b. This will return new array with all the matching letters. If length is zero, no matching chars.
add toUpperCase() to a & b if necessary

So if it only duplicate strings in separate string arrays using .split(''), then I would sort the two string separately, and then do a binary search, start with the array of the shortest length, if the same length the just use the first one, and go character by character and search to see if it is in the other string.

This is obviously too late to matter to the original poster, but anyone else who finds this answer might find this useful.
var a = 'ABCD';
var b = 'DEFG';
function doesNotHaveCommonLetter(string1, string2) {
// split string2 into an array
let arr2 = string2.split("");
// Split string1 into an array and loop through it for each letter.
// .every loops through an array and if any of the callbacks return a falsy value,
// the whole statement will end early and return false too.
return string1.split("").every((letter) => {
// If the second array contains the current letter, return false
if (arr2.includes(letter)) return false;
else {
// If we don't return true, the function will return undefined, which is falsy
return true;
}
})
}
doesNotHaveCommonLetter(a,b) // Returns false
doesNotHaveCommonLetter("abc", "xyz") // Returns true

const _str1 = 'ABCD';
const _str2 = 'DEFG';
function sameLetters(str1, str2) {
if(str1.length !== str2.length) return false;
const obj1 = {}
const obj2 = {}
for(const letter of str1) {
obj1[letter] = (obj1[letter] || 1) + 1
}
for(const letter of str2) {
obj2[letter] = (obj2[letter] || 1) + 1
}
for(const key in obj1) {
if(!obj2.hasOwnProperty(key)) return false
if(obj1[key] !== obj2[key]) return false
}
return true
}
sameLetters(_str1, _str2)

Related

Trouble understanding .indexOf in this code problem

I recently completed this Leetcode assessment for an open-book interview. Luckily I was able to Google for help, and passed the assessment. I'm having trouble understanding what exactly is happening on the line declared below. I'd love it if one of your smartypants could help me understand it better!
Thank you!
The problem:
Have the function NonrepeatingCharacter(str) take the str parameter being passed, which will contain only alphabetic characters and spaces, and return the first non-repeating character. For example: if str is "agettkgaeee" then your program should return k. The string will always contain at least one character and there will always be at least one non-repeating character.
Once your function is working, take the final output string and combine it with your ChallengeToken, both in reverse order and separated by a colon.
Your ChallengeToken: iuhocl0dab7
function SearchingChallenge(str) {
// global token variable
let token = "iuhocl0dab7"
// turn str into array with .split()
let arrayToken = token.split('')
// reverse token
let reverseArrayToken = arrayToken.reverse();
// loop over str
for (var i = 0; i < str.length; i++) {
// c returns each letter of the string we pass through
let c = str.charAt(i);
***--------------WHAT IS THIS LINE DOING?-------------***
if (str.indexOf(c) == i && str.indexOf(c, i + 1) == -1) {
// create variable, setting it to array with first repeating character in it
let arrayChar = c.split()
// push colon to array
arrayChar.push(':')
// push reversed token to array
arrayChar.push(reverseArrayToken)
// flatten array with .flat() as the nested array is only one level deep
let flattenedArray = arrayChar.flat()
// turns elements of array back to string
let joinedArray = flattenedArray.join('')
return joinedArray;
}
}
};
What I'd do is:
Reduce the string to an object, where the keys are the letters and the values are objects containing counts of occurrences and initial index in the string
Sort the .values() of that object in order of minimum count and minimum index
Use the first entry in the result of the sort to return the character
So something like
function firstUnique(str) {
const counts = Array.from(str).reduce((acc, c, i) => {
(acc[c] || (acc[c] = { c, count: 0, index: i })).count++;
return acc;
}, {});
return Object.values(counts).sort((c1, c2) =>
c1.count - c2.count || c1.index - c2.index
)[0].c;
}

Turning a string into an array and saving it as a new array, doesn't return original array

This function cleans up a string (removes all non-alphanumeric characters including underscores) then splits each letter into an array so that it can be reversed, then checked against the original.
At console.log(cleanStr) , it is returning the reversed array but I do not know why.
function checkIfPalindrome(str) {
var cleanStr = str.toLowerCase().replace(replace, "" ).split("");
var reversedStr = cleanStr.reverse();
console.log(cleanStr); // why is this returning reverseStr, the reversed array?
if (cleanStr == reversedStr){
return true
}
return false
}
checkIfPalindrome("five|\_/|four");
The reverse() method reverses an array in place - it mutates the array it's called on. Try creating a new array instead:
const cleanStr = str.toLowerCase().replace(replace, "" ).split("");
const reversedStr = [...cleanStr].reverse();
At console.log(cleanStr) , it is returning the reversed array but I do not know why.
Because reverse reverses it in place.
Separately, you have a problem here:
if (cleanStr == reversedStr){
If they were different arrays, that would always be false, even if they had the same contents.
If you want to make a copy of the array and then reverse it, throw a .slice() in there:
var reversedStr = cleanStr.slice().reverse();
// -----------------------^
...and then compare after turning them back into strings:
if (cleanStr.join("") === reversedStr.join(""))
(I'd probably change those variable names, too, as they don't refer to strings.)
And finally, any time you find yourself writing:
if (x == b) {
return true;
}
return false;
back up and write
return x == b;
instead. :-)

Check if string contains set of other string

I want to check if string one in array contain the letters from words in string 2. Here's my example array:
(["Floor", "far"]);
function should return false because "a" is not in string "Floor"
But for array like this:
(["Newbie", "web"]);
It should return true because all of letters from "web" are in "Newbie".
Here's my code so far...
function mutation(arr) {
var newArr = [];
for (i=0; i<arr.length; i++) {
newArr.push(arr[i].toLowerCase().split(""));
}
for (i=0; i<newArr.length; i++) {
for (j=0; j<newArr[i].length; j++) {
console.log(newArr[0][j]+ (newArr[1][j]));
}
}
}
mutation(["Newbie", "web"]);
I know that it won't work and I'm out of ideas how to make it. I try to make a set of all letters in two array and compare them. If there is at least one false the function should return false. Should I nest indexOf() method somewhere?
I think this should work for you. Break up the string of letters to check for into an array. Iterate over the array getting each letter and checking if the string passed in contains the letter, setting our result to false if it doesn't.
function mutation(arr) {
var charArr = arr[1].toLowerCase().split("");
var result = true;
charArr.forEach(element => {
if (!arr[0].toLowerCase().includes(element)) {
result = false;
}
});
return result;
}
console.log(mutation(["Newbie", "web"]));
The cool way would be:
const mutation =([one, two]) => (set => [...two.toLowerCase()].every(char => set.has(char)))(new Set(one.toLowerCase()));
How it works:
At first we destructure the passed array into the first and the second word:
[one, two]
Now that we got both, we build up a Set of characters from the first word:
(set => /*...*/)(new Set(one))
All that in an IIFE cause we need the set here:
[...two].every(char => set.has(char))
That spreads the second word in an array, so we got an array of chars and then checks if all characters are part of the set we built up from the other word.
If you want to be sure that one word, which might have several repeating letters, is contained in another, use Array.reduce() to count the letters, and store create a map of letter -> counts. Do that for both words. Check if all entries of 2nd word are contained in the 1st word map using Array.every():
const countLetters = (w) =>
w.toLowerCase()
.split('')
.reduce((r, l) => r.set(l, (r.get(l) || 0) + 1), new Map());
const mutation = ([a, b]) => {
const al = countLetters(a);
const bl = countLetters(b);
return [...bl].every(([k, v]) => v <= (al.get(k) || 0));
};
console.log(mutation(["Floor", "far"])); // false
console.log(mutation(["Floor", "for"])); // true
console.log(mutation(["Floor", "foroo"])); // false
console.log(mutation(["Newbie", "web"])); // true

Use reduce function to compare symbol in the two string

I try to compare two strings in array on equal symbols or char,this code works, but how to implement it in ES6 with reduce method, if I have more than two strings an array. I need to return true if the string in the first element of the array contains all of the letters of the string in the second element of the array. But how to create the more flexible function if I have more than 2 elments in the array.
function mutation(arr) {
var arr2 = arr.map(item => item.toLowerCase().split(''));
for (i=0;i<arr2[1].length;i++) {
if (arr2[0].indexOf(arr2[1][i]) < 0)
return false;
}
return true;
}
mutation(["hello", "hey"]);
#Palaniichuk I thought your original algorithm was pretty solid. To handle your request I was able to create a solution that uses reduce.
I do have one question for you. Should the array increase in size, how would the strings be evaluated?
The reason I ask is because using a helper function like this might help you scale this algorithm. Of course it all depends on how the input changes. How the inputs are evaluated.
function makeStr(string) {
const reducer = string.split('').reduce((a, b) => {
a[b] = a[b] + 1 || 1;
return a;
}, {});
return Object.keys(reducer).sort().join('');
}
function secondMutation(arr) {
const array = [...arr].map(makeStr);
return array[0].includes(array[1]);
};
console.log(secondMutation(["hello", "hell"]));

Javascript problems when converting a string to an array and then back again

I am trying to solve a Javascript challenge on Codewars.
An isogram is a word that has no repeating letters, consecutive or non-consecutive. Implement a function that determines whether a string that contains only letters is an isogram. Assume the empty string is an isogram. Ignore letter case.
isIsogram( "Dermatoglyphics" ) == true
isIsogram( "aba" ) == false
isIsogram( "moOse" ) == false // -- ignore letter case
My effort is below:
function isIsogram(str) {
var arr = str.split("");
var seen = {};
var out = [];
var length = arr.length;
var j = 0;
for(var i = 0; i < length; i++) {
var item = arr[i].toLowerCase;
if(seen[item] !== 1) {
seen[item] = 1;
out[j++] = item;
}
}
console.log(out.toString.toLowerCase);
console.log(str.toLowerCase);
if (out.toString.toLowercase === str.toLowerCase) {
return true;
}
else {
return false;
}
}
In codewars the result of my
console.log(out.toString.toLowerCase); is undefined
and the result of
console.log(str.toLowerCase); is [Function: toLowerCase].
This means my solution always evaluates to false.
I would appreciate any help to point me in the right direction or highlight my errors instead of giving me the solution so I can learn more effectively. Thanks!
This may be a simpler answer.
function isIsogram(str){
// Turn all letters of the string to lower case and split it into an array.
var letters = str.toLowerCase().split('');
var checkLetters = [];
/* Check to see if the letter appears in the checkLetters array.
If the letter is not already in the array it will push the letter into it. */
letters.forEach(function(letter) {
if(checkLetters.indexOf(letter) === -1) {
checkLetters.push(letter);
}
});
/* Now we have two arrays. If the letters array has non-duplicate letters then
it will be the same length as the checkLetters array. If not, the checkLetters array
will be shorter. */
/* Return true or false depending on whether the lengths of both arrays are equal */
return letters.length === checkLetters.length ? true : false;
}
toString and toLowerCase are functions. In Javascript, to execute a function, you must add parenthesis on to the end of the function name:
out.toString().toLowerCase()
// ^^ ^^
You need to do this for all your functions:
arr[i].toLowerCase()
str.toLowerCase
out.toString.toLowercase() === str.toLowerCase()
(Note that calling .toString() on an array will include commas, e.g. "a,b,c,d,e". Probably doesn't matter for this use case, but just to highlight that)
toString and toLowerCase etc are functions
use:
out.toString().toLowerCase()
however, for out, I think you want to do out.join('').toLowerCase()
I think that you can improve your solution, by doing in the functional way, using hashmap system, and every method.
The every method executes the provided callback function once for each element present in the array until it finds one where callback returns a falsy value
So, your code will be more clean.
function isIsogram(str) {
//Create our hashmap
var hashmap = {};
//Return value of 'every' loop
return str.split("").every(function(elm){
//If our hashmap get current letter as key
return hashmap.hasOwnProperty(elm.toLowerCase())
//Return false, str is not an Isogram
? false
//Otherwise, set letter as key in our hashmap,
//we can check the next iteration
: hashmap[elm.toLowerCase()] = true;
});
}
console.log(isIsogram('Dermatoglyphics'));
console.log(isIsogram('moOse'));
console.log(isIsogram('aba'));
I know you've solved this, but just for variety.
By ignoring case sensitivity, first change the input to lowercase.
function isIsogram(str) {
// Change word to lower case
str = str.toLowerCase();
// split the word into letters and store as an array
var arr = str.split("");
// get the length so the array can be looped through
var len = arr.length;
// an array to contain letters that has been visited
var seen = []
for (var i = 0; i < len; i++) {
// check if letter has not been visited by checking for the index
if(seen.indexOf(arr[i])<0){
// if the letter doesn't exist,add it to seen and go to next letter
seen.push(arr[i]);
}else{
// if letter exists, the word is not an isogram return false
return false
}
}
// the loop is complete but each letter appeared once, the word is an isogram
return true
}
console.log(isIsogram('Dermatoglyphics'));
console.log(isIsogram('moOse'));
console.log(isIsogram('aba'));

Categories