Check if string contains set of other string - javascript

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

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;
}

is there any way to do array.includes ignoring order?

I want a function that returns 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.
For example, ["hello", "Hello"], should return true because all of the letters in the second string are present in the first, ignoring case.
The arguments ["hello", "hey"] should return false because the string hello does not contain a y.
Lastly, ["Alien", "line"], should return true because all of the letters in line are present in Alien.
Here is the code that i currently have:
function mutation(arr) {
return arr[0].includes(arr[1]);
}
If i insert arguments such as ['dinosaur', 'dino'] or ['coding', 'ding'] it returns true, which is okay.
But if i insert arguments such as ['dinosaur', 'dnour'] or ['coding', 'gnidoc'] it returns false, which i want to return true.
What is the simplest way to accomplish this?
The most efficient way to do this test is to convert the first element of the array into a Set and then check that every character in the second element is in the set:
function mutation(arr) {
first = new Set(arr[0].toLowerCase())
return [...arr[1].toLowerCase()].every(char => first.has(char))
}
console.log(mutation(['hello', 'Hello']));
console.log(mutation(['hello', 'hey']));
console.log(mutation(['Alien', 'line']));
console.log(mutation(['dinosaur', 'dino']));
console.log(mutation(['dinosaur', 'onion']));
console.log(mutation(['coding', 'ding']));
console.log(mutation(['coding', 'gniDoc']));
Sets are guaranteed (by the specification) to have less than O(n) lookup time (and a reasonable implementation will be a hash table which has O(1) lookup time), so this will be faster than a loop using Array.includes.
Note that this code assumes that mutation(['abc', 'aaa']) should be true as the letter a does occur in the first element of the array (just not 3 times).
You're part of the way there. Ideally you want to iterate over the characters in the second word and check that every character is included in the first word.
Note: to use every (an array method) you need to coerce the string to an array of characters which you can do with Array.from or the spread syntax ([...string])
function check([ first, second ]) {
return [...second.toLowerCase()].every(char => {
return first.toLowerCase().includes(char);
});
}
console.log(check(['hello', 'Hello']));
console.log(check(['hello', 'hey']));
console.log(check(['Alien', 'line']));
console.log(check(['dinosaur', 'dino']));
console.log(check(['dinosaur', 'dnour']));
console.log(check(['coding', 'ding']));
console.log(check(['coding', 'gniDoc']));
console.log(check(['coding', 'fuzzycoding']));
One solution could be with two nested loops but that would be a bit slow.
Time complexity will be O(m*n)
Size of the first element: m,
Size of the second element n
This can be improved by using hashMap and indexing the first element letter by counting them.
When letters are counted you can iterate the second element and decrease the counter by comparing it with each letter. When there is no match it will be false.
Finally, you will have the time complexity of O(max(m,n)) which is better than O(m*n)
function mutation([first, second]) {
const idxs = new Map();
for(const f of first) {
const l = f.toLowerCase();
if(!idxs.has(l)) idxs.set(l, 1);
else idxs.set(l, idxs.get(l) + 1);
}
for(const s of second) {
const l = s.toLowerCase();
const val = idxs.get(l);
if(val && val > 0) {
idxs.set(l, idxs.get(l) - 1);
} else {
return false;
}
}
return true;
}
const tests = [
[["hello", "Hello"], true],
[["hello", "hey"], false],
[["Alien", "line"], true],
[['dinosaur', 'dino'], true],
[['dinosaur', 'dnour'], true],
[['coding', 'gnidoc'], true]
];
for(const [parameters, expected] of tests){
const result = mutation(parameters);
console.assert(result === expected, {parameters, expected});
console.log(parameters, result === expected ? 'PASSED': 'FAILED')
}

Each letter once uppercase

javascript function which returns an array of string in such a way that it contains all possible upper-case letters of the input string one at a time sequentially.
uppercase("hello") ➞ ["Hello", "hEllo", "heLlo", "helLo", "hellO"]
what i have tried is
const helloCapital = (str) => {
let a = [];
for (let i in str) {
a.push(str[i].toUpperCase() + str.slice(1));
}
return a;
};
but it gives weird results
[ 'Hello', 'Eello', 'Lello', 'Lello', 'Oello' ]
This looks like a challenge for a course or challenges website.
If that is the case, it is really, really not cool to come here and ask for that answer.
But, since I'm already here, here it goes a working solution.
const capitals = s => Array.from(s,(_,i)=>s.slice(0,i)+_.toUpperCase()+s.slice(i+1))
UPDATE: Explaining the code
Array.from works on iterable objects, such as strings, Arrays and, ArrayLike objects for example.
It calls the function you pass as the first argument on each element of the iterable, in this case, the string.
The function receives 1 element of the iterable (the _) and the position of that element (the i)
So the function is returning a concatenation of 3 things:
* the substring of the original string from 0 to i
* the current element of the iterable, or current character, toUpperCase()
* the substring of the original string from i+1 to the end of the string.
Your logic is wrong, to work you need to concat the slice before letter with capitalized letter and with the slice after letter.
function capitalizeEachLetter (text) {
return Array.from(text, (letter, index) =>
text.slice(0, index) + letter.toUpperCase() + text.slice(index + 1)
);
}
use array array map,
var str = "hello";
var capitals = Array.from(str).map((e, i, ar) => {
let r = [...ar];
r[i] = ar[i].toUpperCase();
return r.join('');
});
console.log(capitals)

How to check if 2 strings separated by delimiters have matching word

Trying to check if 2 strings have matching word return true.
let 1st_string = chin, kore, span;
let 2nd_string = chin eng kore zulu
1st_string.split(',').indexOf(2nd_string) > -1
I tried above code but always returns false. I need to return true as 2_nd string contains 2 matching words from 1st_string.
Solved the names and values of the variables you can do the following
let first_string = 'chin, kore, span';
let second_string = 'chin eng kore zulu';
const array1 = first_string.split(',').map(string => string.trim());
const array2 = second_string.split(' ');
function exist(list1, list2) {
for (const element of list1) {
if (list2.includes(element)) {
return true;
}
}
return false;
}
const result = exist(array1, array2);
console.log(result);
1st_string is not a valid variable name
split the first string and use Array.some() to see if the second string has any of the words in the resulting array :
let string_1 = 'chin, kore, span';
let string_2 = 'chin eng kore zulu';
const check = (str1, str2) => {
return str1.split(',').some(word => str2.includes(word));
}
console.log(check(string_1, string_2))
I think your second string will also contain a comma in between the words if yes then it is easy to achieve.
you can split the string 1 and 2 with a comma as delimiter like this
let firstString = 1st_string.split(',');
let secondString = 2nd_string.split(',');
after doing you will get the firstString and secondString variable as array then you can iterate the first array and check for duplicate using includes methods
for (let i in firstString) {
if(secondString.includes(firstString[i])){
//you can do whatever you want after finding duplicate here;
}
}

How to check if two strings contain same characters in 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)

Categories