Use reduce function to compare symbol in the two string - javascript

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"]));

Related

Recursion question: Create array where each letter occupies an index of the array

I am using javascript.
I am new to recursive functions, and cannot seem to figure out how to express this logic recursively:
" Write a function that accepts a string and creates an array where each letter
// occupies an index of the array. "
(Firstly,) I think the question is asking me to do the following:
'Hello' -> ['H', 'e', 'l', 'l', 'o'];
It is simple enough, but nothing I try seems to be working. I thought the base call could be :
function createArr(str) {
let results = [];
if (str.length === 0) {
return results;
}
and then I would recursively return the last letters of the string, and push them out once the stack is returned, like so:
else {
var letters = createArr(str.slice(str.length-1))
results.push(letters);
return results;
}
}
console.log(createArr('Hello'));
But for some reason nothing seems to be working .. I would really appreciate if someone could clarify this problem for me.
Thanks in advance! :)
You can use recursion with array spread, to create an array, and flatten the results to a single array:
function createArr(str) {
if(!str.length) return []; // return an empty array when the string is empty
return [
str[0], // take the current letter
...createArr(str.slice(1)) // pass the rest of the string to createArr
]
}
console.log(createArr('Hello'));
var createArray = function(str) {
var resultArray = [];
if (str.length === 1) {
resultArray = resultArray.concat(str);
return resultArray;
}
resultArray = resultArray.concat(str[0]);
return resultAray = resultArray.concat(createArray(str.slice(1)));
};
Obviously you can simply use split passing an empty string to perform that operation...
That aside if you wanted to solve this using recursion you can simply pass the result back into the function each time. e.g.
// using split
function createArr1(s) {
return s.split('')
}
console.log(createArr1('hello'))
// using recursion
function createArr2(s, out = []) {
if(!s) return out;
out.push(s[0]);
return createArr2(s.slice(1), out);
}
console.log(createArr2('hello'))

JavaScript Pure function

I wanted to know if this is a pure javascript function.
if it is not I would like to understand the reason.
function reverseArrayInPlace(array1) {
let array2 = [];
for (let i = array1.length - 1; i >= 0; i--) {
array2.push(array1[i]);
}
return array2;
}
Thanks for the help!
Since a pure function must produce the same output given the same input, without side effects, your code is pure (assuming that the array1 parameter will be a plain array, and not something strange like an object with a setter on its length property).
That said, purity is generally an issue to be concerned about in functional contexts, and this is not a functional approach since you're using .push, which mutates the array that you created. A more functional approach would be to use .map to create the array to be returned all in one go, without mutation:
const reverseArray = (arr) => {
const { length } = arr;
return arr.map((_, i) => arr[length - 1]);
};
or Array.from:
const reverseArray = (arr) => {
const { length } = arr;
return Array.from(
arr,
(_, i) => arr[length - 1]
);
};
Also note that all of these implementations return a new array, but they don't reverse the array in place. (Any function which reversed the array in-place would be impure, because that would be a side-effect.) Best to either choose a different name than reverseArrayInPlace, or, if you do want to reverse the array in-place, give up on purity, since it'd be impossible.

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

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)

Opposite of Array.reduce() in javascript

Array.reduce() takes an array and combines elements from the array with an accumulator until all the elements are consumed.
Is there a function (often called "unfold" in other languages) that starts with a value and keeps generating elements until a complete array is produced (the accumulator is depleted)?
I am trying to do this as part of converting between arbitrary bases. The code as I have it is as follows, but I would like to eliminate the raw loop.
var dstAlphabet = "0123456789ABCDEFGH";
var dstBase = dstAlphabet.length;
var wet = BigInteger(100308923948716816384684613592839);
var digits_reversed = [];
while (wet.isPositive())
{
// var digitVal = wet % dstBase
var divRem = wet.divRem(dstBase); // [result of division, remainder]
wet = divRem[0];
digits_reversed.push(dstAlphabet.charAt(divRem[1].toJSValue()));
}
return digits_reversed.reverse().join("");
// These days you can do it in one line:
const unfold = (accumulator, length) => length <= 0 ? accumulator : unfold([length, ...accumulator], length -1)
// invoke it like this:
const results = unfold([], 5)
// expected results: 1,2,3,4,5
console.log(results.join(','))
Since we're looking for a concise way to generate a given number of elements as an array, this "unfold" function does it with recursion.
The first argument is the accumulator array. This needs to be passed along, and eventually is returned when it holds the entire collection. The second argument is the limiter. This is what you use to dimension your resulting array.
In each call, we first test if the base case is reached. If so, the answer is easy: just return the given array. For the general case, we are again unfolding, but with a smaller value, so we prepend one value to accumulator, and decrement length.
Since we're using the spread operator and a 'computed-if' the function is concise. Using the arrow style also lets us avoid the 'function' and 'return' keywords, as well as curly-braces. So the whole thing is a one-liner.
I basically use this technique as a for-loop substitute for React JSX, where everything needs to be an expression (Array.map()).
The opposite of Array#reduce in Javascript is Array.from (or alternatively spread syntax). You can use it with any iterable object to generate an array:
array = Array.from(iterator); // same as array = [...iterator];
You can create an iterator by calling a generator function:
iterator = generate(params);
Generator functions use the special keyword yield to return their results (or yield* to return all results from another iterable). And they are depleted once they return:
function* convertBase(wet, alphabet) {
const base = BigInt(alphabet.length);
wet = BigInt(wet);
while (wet > 0) {
const digitVal = Number(wet % base);
wet = wet / base;
yield alphabet.charAt(digitVal);
}
}
console.log(Array.from(convertBase(100308923948716816384684613592839, "0123456789ABCDEFGH")).reverse().join(""));
Alternatively you can implement the iterator yourself without a generator function:
console.log(Array.from({
wet: BigInt(100308923948716816384684613592839),
base: BigInt(18),
alphabet: "0123456789ABCDEFGH",
[Symbol.iterator]: function() {
return this;
},
next: function() {
if (this.wet > 0) {
const digitVal = Number(this.wet % this.base);
this.wet = this.wet / this.base;
return {value: this.alphabet.charAt(digitVal)};
} else {
return {done: true};
}
}
}).reverse().join(""));
tewathia's comment seems like the idiomatic way to do it, but I guess if you want to do it the hard way, you could just write your own recursive primitive, like:
function unreduce(accumulator, operation, stopPredicate, ret) {
return helper([accumulator, ret])[1]
function helper(vals) {
if (stopPredicate(vals[0])) return vals[1];
return helper(operation(vals[0], vals[1]));
}
}
Which you might want to modify a bit to preserve this for the callbacks.
I'm not sure how great that is. It's kind of awkward with the operation callback needing to update both the accumulator and return values. The outer function can't save operation from having to return a length-2 array.
array.map((..) => { return [ .. ]; }).flat(1);

Categories