HackerRank problem PlusMinus using for-loop - javascript

I need very specific answer to this particular HackerRank problem : https://www.hackerrank.com/challenges/plus-minus/problem.
Why this code is passing all the test-cases ?
function plusMinus(arr) {
let positives = 0
let negatives = 0
let zeros = 0
const length=arr.length
for (var i = 0; i < arr.length;i++){
if (arr[i] > 0) {
positives++
} else if (arr[i] < 0) {
negatives++
} else {
zeros ++
}
}
const positiveRatio = Number(positives / length).toFixed(6)
const negativeRatio = Number(negatives / length).toFixed(6)
const zeroRatio = Number(zeros / length).toFixed(6)
console.log(positiveRatio)
console.log(negativeRatio)
console.log(zeroRatio)
}
And why this code is not passing any test-case ?
(I have edited my code: sorry for earlier wrong code) This code also does not works.
function plusMinus(arr) {
var l = arr.length;
var positiveCounter = 0;
var negativeCounter = 0;
var zeroCounter = 0;
for(var i=0; i<=l; i++) {
if (arr[i]>0) {
positiveCounter+=1;
} else if (arr[i]<0) {
negativeCounter+=1;
} else {
zeroCounter+=1;
}
}
console.log (
(positiveCounter/l).toFixed(6)+ '\n' +(negativeCounter/l).toFixed(6)+ '\n' +(zeroCounter/l).toFixed(6) );
}
I don't want alternative ways to solve this. I just want to know why the first code works and the second code doesnt ???

These 2 codes are different, you are dividing the numbers by the length twice
First in the assignment to a variable (var p= ...)
Second when doing the console.log ((p/l).toFixed(6))
Also, like mentionned by #DhananjaiPai, they have multiple console.log and you only have one with breaking characters which can be differently interpreted by OS (\r\n or \n )
You also have a something wrong in your loop, I will let you find that one but remember that an array begin from the index 0, if the array has 3 elements, that will be [0, 1, 2]

Related

JavaScript for loop that alternates two constants

I've been trying to use a for loop to make a code that alternates between two strings and ends with .toUpperCase , but I'm completely stuck. I'm "able" to do it with an array with two strings (and even so it has a mistake, as it ends with the first string of the array...), but not with two separate constants.
Could anyone offer some help?
function repeteFrases(num) {
const frases = ["frase um", "frase dois"];
let result = "";
for (let i = 0; i < num; i++) {
result += i === num - 1 ? frases[0].toUpperCase() : `${frases[0]}, ${frases[1]}, `;
}
return result;
}
console.log(repeteFrases(2));
In order to alternate between two states you can use the parity of the index, i.e., the condition would be i % 2 == 0, like this:
function repeteFrases(num) {
const frases = ["frase um", "frase dois"];
let result = "";
for (let i = 0; i < num; i++) {
result += i % 2 == 0 ? frases[0].toUpperCase() : `${frases[0]}, ${frases[1]}, `;
}
return result;
}
console.log(repeteFrases(5));
You've almost got it.. I think what you're asking for is to repeat phrase one or two (alternating), and for the last version to be uppercase. I notice someone else made your code executable, so I might be misunderstanding. We can test odd/even using the modulus operator (%), which keeps the access of frases to either the 0 or 1 position. The other trick is to loop until one less phrase than needed, and append the last one as upper case.
function repeteFrases(num) {
const frases = ["frase um", "frase dois"];
//Only loop to 1 less than the expected number of phrases
const n=num-1;
let result = "";
for (let i = 0; i < n; i++) {
//Note %2 means the result can only be 0 or 1
//Note ', ' is a guess at inter-phrase padding
result+=frases[i%2] + ', ';
}
//Append last as upper case
return result+frases[n%2].toUpperCase();
}
console.log(repeteFrases(2));
console.log(repeteFrases(3));
Use frases[i % frases.length] to alternate the phrases (however many there might be)
function repeteFrases(num) {
const frases = ["frase um", "frase dois"];
let result = "";
for (let i = 0; i < num; i++) {
const next = frases[i % frases.length];
const isLast = (i === num - 1);
result += isLast ? next.toUpperCase() : `${next}, `;
}
return result;
}
console.log(repeteFrases(5));

Not able to access the value of variable inside the loop

I am trying to run below code and expecting 14 on console but I am getting nothing, I don't know why, can any one please tell me.
let array = ['O','Q','R','S'];
let missingLetter = '';
let isUpperCase = false;
const engAlphabets = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n',
'o','p','q','r','s','t','u','v','w','x','y','z'];
// Find 1st letter index in the engAlphabets array
const arrayFirstLetter = array[0].toLowerCase();
const firstIndex = engAlphabets.indexOf(arrayFirstLetter);
// Find the missing letter in the array
let j=0;
for(let i=firstIndex; i<array.length; i++) {
console.log(i); // it should be 14 but, there is nothing on console.
let arrayInputLetter = array[j].toLowerCase();
j += 1;
if(engAlphabets[i] !== arrayInputLetter) {
missingLetter = engAlphabets[i];
break;
}
}
First of all, the for-loop isn't even entered, because i is less than array.length from the start, as decezeā™¦ and zhulien pointed out in the comments. If I understand your goal, you would want i to be 0 in the beginning, so the for-loop iterates over array.
Then it also seems like you sometimes unintentionally swapped i and j in the end. As you can see, j isn't even needed...
And the boolean isUpperCase isn't used after being initialized, so you can just remove it from your code.
let array = ['O','Q','R','S'];
let missingLetter = '';
const engAlphabets = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n',
'o','p','q','r','s','t','u','v','w','x','y','z'];
const arrayFirstLetter = array[0].toLowerCase();
const firstIndex = engAlphabets.indexOf(arrayFirstLetter);
for (let i = 0; i < array.length; i++) {
let arrayInputLetter = array[i].toLowerCase();
if (engAlphabets[firstIndex + i] !== arrayInputLetter) {
missingLetter = engAlphabets[firstIndex + i];
break;
}
}
console.log(missingLetter);
In your for, i start with 14 (firstIndex) and increasing while lower than 4 (array.length). So codes inside the for block do not run.

Passing hands of cards around a table in Javascript

This seems like a stupidly simple thing to do, but I can't figure out what I'm doing wrong. The goal is to have an array of 8 other arrays, which each contain hands of cards (in the example, the arrays just contain arbitrary numbers). Then, depending on whether passDirection is set to -1 or 1, each array is cycled through and replaced with the one next to it. The desired end result is that the values of playerList essentially shift by 1 either up or down, and this can be repeated several times without issue.
What's actually happening with the code I have below, though, is that all the arrays are just being replaced with what's at index 0, except for the first one. How can I fix this?
var playerList = new Array;
var passDirection = -1;
for(i = 0; i < 8; i++) {
playerList.push([playerList.length,i]); // Fill Arrays with arbitrary data
}
for (i=0; i< playerList.length; i++) {
console.log(i + ": " + playerList[i]); // Check their values before anything is done to them
}
for(q=0; q < 5; q++){ // Repeat the process 5 times, just because.
var bufferArray = playerList[0]; // Put Array Element 0's value in a buffer as it will be replaced first
for(i = 0; i < playerList.length && i > (playerList.length * -1); i += passDirection) {
var catcher = i; // 'catcher' should be the array that gets replaced
var passer = catcher - passDirection; // 'passer' should be the one it gets replaced with
if (catcher < 0) {
catcher = catcher + playerList.length;
}
if (passer < 0) {
passer = passer + playerList.length;
} else if (passer >= playerList.length) {
passer = passer - playerList.length;
}
if (passer == 0) {
playerList[catcher] = bufferArray;
} else {
playerList[catcher] = playerList[passer];
}
}
for (i=0; i< playerList.length; i++) {
console.log(i + ": " + playerList[i]);
}
console.log("...");
}
https://jsfiddle.net/3r1Lhwc5
You have two errors in your code:
if (passer = 0) is performing an assignment. You need if (passer === 0).
The passer index is looking at the wrong side of the value. Currently you are first getting from 1 and putting at 0, then getting from 0 and putting at 7 (i.e. -1). Notice how you are moving the same value in the second iteration. You need to change passer = catcher - passDirection to passer = catcher + passDirection
Note that all this can be done much easier with the splice, shift, unshift, pop and push Array methods (on the main playerList).
You can make your life easier by using Array methods to move elements from the beginning to end of an array or vice versa. Using this in the body of your for loop should do the trick:
if (passDirection === -1) {
const first = playerList.shift();
playerList.push(first);
}
else {
const last = playerList.pop();
playerList.unshift(last);
}

Logical error keeps for loop looping infinite, Why?

I'm trying to build a JavaScript devowelizer, but I'm producing an infinite loop.
I'm hoping someone on Stack Overflow can help?
The code =>
let userWord = prompt("Type a word to devowelize: ");
userWord = Devowelize(userWord);
alert(userWord);
function Devowelize(word) {
for (let i = 0; i <= word.length; i++) {
let eatChars = "aeiou"
for (let i2 = 0; i2 <= eatChars.length;) {
if (word[i] == eatChars[i2] &&
word[i] != "") {
word = word.replace(word[i], "");
} else {
i2++;
}
}
}
return word
}
You are using here for (let i = 0; i <= word.length; i++) this part i <= word.length isn't correct because you will try to access the array word using the i index after that in your code so in the last iteration you will access an index which is not defined by your array the last index of an array in javascript is always arrayLength-1 if you access an item which is out of the array you will get an undefined as value which will generates an infinte loop in your case you have done the same thing here for (let i2 = 0; i2 <= eatChars.length;) but the first loop is the responsible of the infinite loop in your code
Your solution is almost there, but you're trying to solve this problem in a very roundabout way. Let's make it a bit easier to understand.
In JavaScript, you can easily check if a string contains another string. For example, if we wanted to check if a character was in a string, we could do this:
let eatChars = "aeiou"
eatChars.includes('e') === true
So knowing that we can do that in a single statement, let's reuse some of the code you've got and substitute the character 'e' for the characters in your word.
let outWord = ""
const eatChars = "aeiou"
// '<= word.length' becomes this, because the string positions only go up to 'word.length - 1
for (let i = 0; i < word.length; i++) {
if (!eatChars.includes(word[i])) { // so the character isn't a vowel
outWord += word[i]
}
}
return outWord
The comments mention learning about 'map' and 'filter'. I'd recommend using a reducer for this if you wanted to be fancy! You could try something like this:
const devowel = (word) => Array.from(word).reduce((out, currentCharacter) => ...)

Removing zeros after comma based on maximum consequent zeros

I have a page with a grid where user's numbers get saved. It has a following pattern - every number ends with 3 digits after comma. It doesn't look nice, when for example user's input is
123,450
123,670
123,890
It's much better to have just 2 numbers after comma, because last 0 is absolutely meaningless and redundant.
The way it still should have 3 digits is only if at least one element in an array doesn't end up with 0
For example:
123,455
123,450
123,560
In this case 1st element of the array has the last digit not equal to 0 and hence all the elements should have 3 digits. The same story with 2 or 1 zeros
Zeros are redundant:
123,30
123,40
123,50
Zeros are necessary:
123,35
123,40
123,50
The question is how can I implement it programatically? I've started like this:
var zeros2Remove = 0;
numInArray.forEach(function(item, index, numInArray)
{
var threeDigitsAfterComma = item.substring(item.indexOf(',') + 1);
for(var j = 2; j <= 0; j--)
{
if(threeDigitsAfterComma[j] == 0)
{
zeros2Remove =+ 1;
}
else //have no idea what to do..
}
})
Well in my implementation I don't know how to do it since I have to iterate through every element but break it if at least 1 number has a last digit equal to zero.. In order to do that I have to break outer loop, but don't know how and I'm absolutely sure that I don't have to...
I think the following code what you are looking for exactly , please manipulate numbers and see the changes :
var arr = ["111.3030", "2232.0022", "3.001000", "4","558.0200","55.00003000000"];
var map = arr.map(function(a) {
if (a % 1 === 0) {
var res = "1";
} else {
var lastNumman = a.toString().split('').pop();
if (lastNumman == 0) {
var m = parseFloat(a);
var res = (m + "").split(".")[1].length;
} else {
var m = a.split(".")[1].length;
var res = m;
}
}
return res;
})
var maxNum = map.reduce(function(a, b) {
return Math.max(a, b);
});
arr.forEach(function(el) {
console.log(Number.parseFloat(el).toFixed(maxNum));
});
According to MDN,
There is no way to stop or break a forEach() loop other than by throwing an exception. If you need such behavior, the forEach() method is the wrong tool. Use a plain loop or for...of instead.
If you convert your forEach loop to a for loop, you can break out of it with a label and break statement:
// unrelated example
let i;
let j;
outerLoop:
for (i = 2; i < 100; ++i) {
innerLoop:
for (j = 2; j < 100; ++j) {
// brute-force prime factorization
if (i * j === 2183) { break outerLoop; }
}
}
console.log(i, j);
I gave you an unrelated example because your problem doesn't need nested loops at all. You can find the number of trailing zeroes in a string with a regular expression:
function getTrailingZeroes (str) {
return str.match(/0{0,2}$/)[0].length;
}
str.match(/0{0,2}$/) finds between 0 and 2 zeroes at the end of str and returns them as a string in a one-element array. The length of that string is the number of characters you can remove from str. You can make one pass over your array of number-strings, breaking out when necessary, and use Array.map as a separate truncation loop:
function getShortenedNumbers (numInArray) {
let zeroesToRemove = Infinity;
for (const str of numInArray) {
let candidate = getTrailingZeroes(str);
zeroesToRemove = Math.min(zeroesToRemove, candidate);
if (zeroesToRemove === 0) break;
}
return numInArray.map(str => str.substring(0, str.length - zeroesToRemove);
}
All together:
function getTrailingZeroes (str) {
return str.match(/0{0,2}$/)[0].length;
}
function getShortenedNumbers (numInArray) {
let zeroesToRemove = Infinity;
for (const str of numInArray) {
let candidate = getTrailingZeroes(str);
zeroesToRemove = Math.min(zeroesToRemove, candidate);
if (zeroesToRemove === 0) break;
}
return numInArray.map(str => str.substring(0, str.length - zeroesToRemove));
}
console.log(getShortenedNumbers(['123,450', '123,670', '123,890']));
console.log(getShortenedNumbers(['123,455', '123,450', '123,560']));
This solution might seem a little cumbersome but it should work for all possible scenarios. It should be easy enough to make always return a minimal number of decimals places/leading zeros.
I hope it helps.
// Define any array
const firstArray = [
'123,4350',
'123,64470',
'123,8112390',
]
const oneOfOfYourArrays = [
'123,30',
'123,40',
'123,50',
]
// Converts 123,45 to 123.45
function stringNumberToFloat(stringNumber) {
return parseFloat(stringNumber.replace(',', '.'))
}
// For 123.45 you get 2
function getNumberOfDecimals(number) {
return number.split('.')[1].length;
}
// This is a hacky way how to remove traling zeros
function removeTralingZeros(stringNumber) {
return stringNumberToFloat(stringNumber).toString()
}
// Sorts numbers in array by number of their decimals
function byNumberOfValidDecimals(a, b) {
const decimalsA = getNumberOfDecimals(a)
const decimalsB = getNumberOfDecimals(b)
return decimalsB - decimalsA
}
// THIS IS THE FINAL SOLUTION
function normalizeDecimalPlaces(targetArray) {
const processedArray = targetArray
.map(removeTralingZeros) // We want to remove trailing zeros
.sort(byNumberOfValidDecimals) // Sort from highest to lowest by number of valid decimals
const maxNumberOfDecimals = processedArray[0].split('.')[1].length
return targetArray.map((stringNumber) => stringNumberToFloat(stringNumber).toFixed(maxNumberOfDecimals))
}
console.log('normalizedFirstArray', normalizeDecimalPlaces(firstArray))
console.log('normalizedOneOfOfYourArrays', normalizeDecimalPlaces(oneOfOfYourArrays))
Try this
function removeZeros(group) {
var maxLength = 0;
var newGroup = [];
for(var x in group) {
var str = group[x].toString().split('.')[1];
if(str.length > maxLength) maxLength = str.length;
}
for(var y in group) {
var str = group[y].toString();
var substr = str.split('.')[1];
if(substr.length < maxLength) {
for(var i = 0; i < (maxLength - substr.length); i++)
str += '0';
}
newGroup.push(str);
}
return newGroup;
}
Try it on jsfiddle: https://jsfiddle.net/32sdvzn1/1/
My script checks the length of every number decimal part, remember that JavaScript removes the last zeros in a decimal number, so 3.10 would be 3.1, so the length is less when there is a number with zeros in the end, in this case we just add a zero to the number.
Update
I've updated the script, the new version adds as much zeros as the different between the max decimal length and the decimal length of the analyzed number.
Example
We have: 3.11, 3.1423, 3.1
The max length would be: 4 (1423)
maxLenght (4) - length of .11 (2) = 2
We add 2 zeros to 3.11, that will become 3.1100
I think you can start out assuming you will remove two extra zeros, and loop through your array looking for digits in the last two places. With the commas, I'm assuming your numArray elements are strings, all starting with the same length.
var numArray = ['123,000', '456,100', '789,110'];
var removeTwo = true, removeOne = true;
for (var i = 0; i < numArray.length; i++) {
if (numArray[i][6] !== '0') { removeTwo = false; removeOne = false; }
if (numArray[i][5] !== '0') { removeTwo = false; }
}
// now loop to do the actual removal
for (var i = 0; i < numArray.length; i++) {
if (removeTwo) {
numArray[i] = numArray[i].substr(0, 5);
} else if (removeOne) {
numArray[i] = numArray[i].substr(0, 6);
}
}

Categories