Comparing values between two arrays - javascript

I'm trying to set up a function that checks if a word or a text is a palindrome. To do that, it splits the text so that every letter is an element of a new array, it takes rid of the white spaces and it makes the reverse array.
Then it checks if every element of the two arrays, at the same positions, are equal. If not it returns false, if yes it returns true.
Here the function:
function palindrome(str) {
var low = str.toLowerCase();
var newArray = low.split("");
var noSpace = newArray.filter(function(val) {
return val !== " ";
});
var reverse = noSpace.reverse();
function check (a, b) {
console.log(`checking '${a}' against '${b}'`);
var partial;
var result = 1;
for (var i = 0; i < a.length; i++) {
console.log(`comparing '${a[i]}' and '${b[i]}'`);
if (a[i] !== b[i]) {
result = 0;
} else {
partial = 1;
result *= partial;
}
}
return result;
}
var result = check(noSpace, reverse);
if (result == 1) {
return true;
} else {
return false;
}
}
palindrome("r y e");
I don't know what's wrong but it seems that the function keeps on returning a true value no matter what word or text I pass to the function. What is wrong with that?

Your issue seems to be because reverse() changes the actual array as well. So doing
var reverse = noSpace.reverse();
Will reverse noSpace and assign a reference to it on the variable reverse. That is, both arrays will be the same (reversed) array.
To bypass that, I've used .slice() to create a copy of the original array, and then called .reverse() on that new array, ridding you of any conflicts.
Here's a working snippet of what it looks like:
function palindrome(str) {
var str_array = str.toLowerCase().split("");
var no_space = str_array.filter(function(val) {
return val !== " ";
});
// By applying '.slice()', we create a new array
// reference which can then be reversed and assigned
// to the 'reverse' variable
var reverse = no_space.slice().reverse();
function check(a, b) {
var partial;
var result = 1;
for(var i=0; i < a.length; i++) {
if(a[i] !== b[i]) {
// We don't need to keep
// comparing the two, it
// already failed
return 0;
} else {
// I've kept this part even though
// I don't really know what it is
// intended for
partial = 1;
result *= partial;
}
}
return result;
}
return check(no_space, reverse) === 1;
}
console.log(palindrome("a b a"));
console.log(palindrome("r y e"));

The way you have coded for palindrome is way too complicated.
But there is one problem with your code: when you do a reverse() it changes the original array as well.
So you will need to make sure that you copy it via slice().
Also you can directly send a boolean result rather than doing a 1 and 0.

At result *= partial;, 1 * 1 will always equal 1

I didn't correct your code, but here is a optimized solution for you.
function palindrom(string) {
var arr = string.split("");
var lengthToCheck = Math.floor(arr.length / 2);
for (var i = 0; i < lengthToCheck; i++) {
if (arr[i] != arr[arr.length - (1 + i)]) {
return false;
}
}
return true;
}
First I split the array after every charater of the passed String. After that I get the half of the length of the array as it's enough to check just one half.
With the for-loop I compare the first half with the second half. As soon as I found two characters that do not match I return false. In case the whole first half matches the second half of the array, the for-loop will be completed and after that true will be returned.

What's actually happening is .reverse() reverses an array in place, it then stores a reference to that array which is not what you're calling in your check() method.
Simple fix would be to change your if statement:
if (a[i] !== b.reverse()[i])

Related

Can a JavaScript loop, upon the second iteration, iterate from the result of the prior iteration?

I just joined Stack Overflow and this is my first post so please do not hesitate to let me know if I am doing anything wrong.
I was presented with a challenge to create a function that accepts a string and calls another given function which swaps indices until the string is returned backwards.
I have gotten as far as below:
//given function
function swap(str, first, last){
str = str.split('');
let firstIndex = str[first];
str[first] = str[last];
str[last] = firstIndex;
str = str.join("").toString()
return str;
}
//my function
let word = "Hello"
function reverseSwap(str) {
let result = ""
for (let i = 0; i < str.length/2; i++) {
result += swap(str, i, str.length -1 - i);
}
return result;
}
console.log(reverseSwap(word))
This however returns "oellHHlleoHello", because each iteration swaps indices from the original string then concatenates. Is it possible, upon the second iteration, to have the loop iterate from the result of the prior iteration so the following occurs?:
result of first iteration: swap(word, 0, 4) which returns "oellH"
second iteration uses "oellH" instead of "Hello" to swap(1, 3) which returns "olleH"
Then, swap(2,2) which doesn't change anything.
It's not working because
Don't += add all new strings to your result. (This will append each swap string to your result.)
You have to manipulate always the "result" string. (You want to do a swap always on the updated version of the string. Not the original one)
Here is a simple solution:
function swap(str, first, last) {
str = str.split("");
let firstIndex = str[first];
str[first] = str[last];
str[last] = firstIndex;
str = str.join("").toString();
return str;
}
let word = "Hello";
function reverseSwap(str) {
for (let i = 0; i < str.length / 2; i++) {
str = swap(str, i, str.length - 1 - i);
}
return str;
}
console.log(reverseSwap(word));

Returning NULL from an empty array

I'm currently learning basic web development with JavaScript, taking an online course which corrects code using a bot. I'm trying to implement a function which calculates the average value of an array.
let numbers = [1,2,3]
function average(array){
var total = 0;
var count = 0;
array.forEach(function(item){
total += item;
count++;
})
if (numbers.length > 0){
return total / count;
} else if (numbers = ([])) {
return null
}
}
The code works fine, in practice, but I get an error returned saying 1) defines average such that average([]) returns null, as in if an empty array is sent in, average([]) is supposed to return null I can't figure out how to fix it...
I would make it way more simpler without the counter. You have the total in the length of the array.
I also added a version using array.reduce().
And please, don't use numbers variable inside the function. It makes no sense here. You pass the variable to the function and inside the function you should use the received variable or it will behave incorrectly. Inside the function numbers is called "arr", so use arr all the way.
function average(arr){
if (arr.length === 0) return null;
let total = 0;
arr.forEach(function(item){
total += item;
})
return total / arr.length;
}
// using array.reduce() which makes more sense here
function average2(arr){
if (arr.length === 0) return null;
const total = arr.reduce(function(prev,next){
return prev + next;
});
return total / arr.length;
}
console.log(average([]));
console.log(average([1,2,3]));
console.log(average2([]));
console.log(average2([1,2,3]));
You don't need to test for []. If the array has a length of zero, then it's empty:
let numbers = [1, 2, 3]
function average(array) {
var total = 0;
var count = 0;
// No need to iterate over array if it's empty
if (array.length > 0) {
array.forEach(function(item) {
total += item;
count++;
})
return total / count;
} else {
// If we got here, array.length === 0
return null
}
}
console.log(average(numbers));
numbers = [];
console.log(average(numbers));
In the second case, numbers = ([]) assigns the numbers to [] (which always return true) instead of comparing it. The right way would be using == as follows:
let numbers = [1,2,3]
function average(array){
var total = 0;
var count = 0;
array.forEach(function(item){
total += item;
count++;
})
if (array.length > 0){
return total / count;
} else if (array.length == 0) {
return null
}
}
console.log(average(numbers));
numbers = [];
console.log(average(numbers));
EDIT:
As mentioned in the comment, there is another mistake, where you are using numbers instead of array in the function.
The reason, why your test case fails, is that you define numbers at the top and then reuse it within the function. That way it always returns the same. You should use array within the function instead.
Here a short version of your script to see, what js is capable of.
function average(array){
let total = array.reduce((acc, value) => acc + value, 0);
return array.length > 0 ? total / array.length : null;
}
console.log(average([1,2,3]))
console.log(average([]))
You are using numbers instead of array inside average() method.
It could be possible that your array can be undefined. Try using this
function average(array) {
if (typeof array == "object" && array.length > 0) {
var total = 0;
var count = 0;
array.forEach(function(item) {
total += item;
count++;
});
return total / count;
} else {
return null;
}
}

Problems with finding unique values in regEx

I have a javascript regEx that is supposed to find all values with curly brackets around them eg {} and return a list of the unique values. I thought that it was working perfectly but I found that it doesn't work depending on the sequence of values.
For example: If the target document contains {lorem}{lorem}{ipsem}{ipsem} the script logs what's wanted [lorem, ipsem] but {lorem}{ipsem}{ipsem}{lorem} the script logs [lorem, ipsem,lorem]. What am I doing wrong!?
function getVariables() {
var doc = DocumentApp.getActiveDocument();
var str = doc.getText(); //get the text of the document
var result = str.match(/{.*?}/g).map(function(val) {
return val.replace(/[\])}[{(]/g, "");
//return val.replace(/(^.*\[|\].*$)/g,'');
});
//The purpose of sort_unique is to find one of every value or string represented in an array
function sort_unique(arr) {
if (result.length === 0) return arr;
arr = arr.sort(function(a, b) {
return a * 1 - b * 1;
});
var ret = [arr[0]];
for (var i = 1; i < arr.length; i++) {
if (arr[i - 1] !== arr[i]) {
ret.push(arr[i]);
}
}
for (var index = 0; index < ret.length; index++) {
Logger.log(ret[index]);
}
return ret;
}
result = sort_unique(result);
Logger.log("Getting final result for front end....");
Logger.log(result);
return result;
}
I believe part of your problem is the sort method. If you replace
arr = arr.sort(function(a, b) {
return a * 1 - b * 1;
});
with
arr = arr.sort();
Then the function appears to work, at least on my side.
This will run in O(n log n) time. You can do better without sorting, if you store the values you've found so far in a map instead of an array. This would run in linear time.
(Also you'll want to replace if (result.length === 0) return arr; with if (arr.length === 0) return arr; just to make your sort_unique function completely independent of the surrounding function.)
The simplest method would be to use a Set. Store each of the regex matches in a set, then return Array.from(mySet).
var mySet = new Set();
str.match(/{.*?}/g).forEach(function(val) {
mySet.add(val.replace(/[\])}[{(]/g, ""));
});
return Array.from(mySet);
A set's add() function is O(1) so the total running time is O(n) where n is the number of matches in your string. Though, realistically, the regex search will be where most of the processing time occurs.
You check if the subsequent items are the same and those that are not subsequent land in the resulting array.
Check if the found value is in the result, and if not add the match, else, ignore.
Use the code like
function getVariables() {
var doc = DocumentApp.getActiveDocument();
var str = doc.getText(); //get the text of the document
var m, result=[], rx = /{([^{}]*)}/g;
while (m=rx.exec(str)) {
if (result.indexOf(m[1]) == -1) {
result.push(m[1]);
}
}
result.sort(); // If you really want to sort use this
// Logger.log(result); // View the result
}
The /{([^{}]*)}/g regex matches {, then captures into Group 1 zero or more chars other than { and }. So, the value you need is in m[1]. The if (result.indexOf(m[1]) == -1) checks if the value is in result.

Javascript How to identify if all elements of one array are present in another

I need to create a function to check if all the letters in the second string of a two string array are present in the first string. The function I wrote seems to work for most of the examples I tried with it but ["hello" , "hey"] returns true despite there not being a y in hello and I don't understand why.
Here's my code:
function mutation(arr) {
arr[0] =arr[0].toUpperCase().split("");
arr[1] =arr[1].toUpperCase().split("");
for(i=0;i<arr[1].length;i++){
if(arr[0].indexOf(arr[1][i])>=0){
return true;
} else {return false;}}}
mutation(["hello", "Hey"]);
You are returning true even if one character is matched ,Try below code it checks if all characters are present or not
function mutation(arr) {
arr[0] = arr[0].toUpperCase().split("");
arr[1] = arr[1].toUpperCase().split("");
var count = 0;
for (i = 0; i < arr[1].length; i++) {
if (arr[0].indexOf(arr[1][i]) >= 0) {
count++;
}
}
return count === arr[1].length
}
mutation(["hello", "Hey"]);
here is one more efficient solution, it works only for lowercase letters.
(function(){
function charCode(str, i){
return str.charCodeAt(i) - 97;
}
function isMutation(a,b){
const aArr = new Uint8Array(26);
const bArr = new Uint8Array(26);
let i=0;
let index = 0;
while(i<a.length){
++aArr[charCode(a, i)];
++i;
}
i = 0;
while(i<b.length){
++bArr[charCode(b, i)];
++i;
}
i = 0;
while(i < 26){
if(!(aArr[i]===0 && bArr[i]===0 || aArr[i]>0 && bArr[i]>0)){
return false
}
++i;
}
return true;
}
console.assert(isMutation('hello', 'oleh') === true);
console.assert(isMutation('hello', 'hey') === false);
})();
you can also compare sum of uniq chars in the both arrays, but in this case you have to add each letters only once.
I would recommend using one of the code solutions suggested by user georg at Remove Duplicates from JavaScript Array.
For example, the function below could be used to sort each array (arr[0] and arr[1]) and remove duplicates.
Credit to user georg at the link above.
function uniq(a) {
return a.sort().filter(function(item, pos, ary) {
return !pos || item != ary[pos - 1];
})
}
Once you have sorted/removed duplicates, you can test to see if the two returned strings are equal or not.
Hello => EHLO, and Hey => EHY
EHLO !== EHY

Permutations filtered with no repeating characters

This is a task from freeCodeCamp.
My goal is to create a function which:
Takes any string with any characters.
Creates an array with all the permutations possible out of that string.
Filters the array and returns only the strings which don't have repeated consecutive letters.
Return the number of total permutations of the provided string that don't have repeated consecutive letters. Assume that all characters in
the provided string are each unique. For example, aab should return 2
because it has 6 total permutations (aab, aab, aba, aba, baa, baa),
but only 2 of them (aba and aba) don't have the same letter (in this
case a) repeating.
I can't figure out what have i wrote wrong. I think the problem lies either in the filter function or the permutation list is faulty.
function permAlone(str) {
if (str.length == 1) {
return str;
}
// Creates all possible Permutations and pushes to an array
var arr = [];
var p = 0; // position of the element which needs to be swapped
// Loop count equal to number of Permutations.
var loops = factorialize(str.length);
for (var i = 0; i < loops; i++) {
// if the position is not the last element in the strig keep swapping with next following character
if (p != str.length - 1) {
var splitStr = str.split('')
arraySwapElements(splitStr, p, p + 1);
str = splitStr.join('');
arr.push(str);
p += 1;
// when position is at the last index, change position to 0
} else {
p = 0;
i -= 1;
}
}
// swaps 2 items in an array
function arraySwapElements(arr, a, b) {
var item = arr[a];
arr[a] = arr[b];
arr[b] = item;
};
// outputs a factorial of a number
function factorialize(num) {
if (num === 0) {
return 1;
} else {
return num * factorialize(num - 1);
}
}
// filters any array which has 2 or more repeating characters
var x = arr.filter(function(str) {
var re = /(.)\1+/;
var result = re.test(str);
if (!result) {
return str;
}
})
// returns the filtered arrays length
return x.length
}
console.log(permAlone('abfdefa'));
When testing:
permAlone("aab") should return a number. // Correct
permAlone("aab") should return 2. // Correct
permAlone("aaa") should return 0. // Correct
permAlone("aabb") should return 8. // Correct
permAlone("zzzzzzzz") should return 0.// Correct
permAlone("a") should return 1.// Correct
permAlone("aaab") should return 0.// Correct
permAlone("abcdefa") should return 3600. // Incorrect
permAlone("abfdefa") should return 2640.// Incorrect
permAlone("aaabb") should return 12. // Incorrect
The issue stems from the logic used in the for loop. While the loop does generate the right number of total permutations, it doesn't generate all permutations.
For example, if our string to be permuted was "abcd", the swapping mechanism would generate strings like this:
bacd bcad bcda
cbda cdba cdab
dcab dacb dabc
adbc abdc abcd
Uh oh! That last arrangement is the same as the starting string. When we start swapping again, we're going to get the same set that we did on the first pass. We're never going to get a permutation like "acbd". Thus the resulting array contains higher numbers of some permutations and lower numbers of others.
I'm not sure how to fix it with the approach you're using, but a recursive function to get permutations could be written like this:
// Returns an array of all permutations of a string
function getPerms(str) {
// Base case. If the string has only one element, it has only one permutation.
if (str.length == 1) {
return [str];
}
// Initialise array for storing permutations
let permutations = [];
// We want to find the permutations starting with each character of the string
for (let i = 0; i < str.length; i++) {
// Split the string to an array
let splitStr = str.split('');
// Pull out the character we're checking for permutations starting with
let currentElem = splitStr.splice(i, 1)[0];
// Get permutations of the remaining characters
let subPerms = getPerms(splitStr.join(''));
// Concat each of these permutations with the character we're checking
// Add them to our list
subPerms.forEach(function (combination) {
permutations.push(currentElem.concat(combination));
});
}
// return our list
return combinations;
}

Categories

Resources