Possible bug/misunderstanding of splice and slice - javascript

I have the next loop:
rolling_average_delta_follower=[];
followers=[32,34,36,38,40,42,44,46,48,50,52,54,56] // .length = 12
delta_followers=[50,52,54,56,58,60,62,64,66,68,70,72,74] // leng= 12
for (i = 0; i < followers.length ; i++) {
copie = delta_followers.slice(0); //creates duplicate of array delta_followers so I keep source original and not cut from it
copie.splice(7,i) // supposed to create an array that contains numbers from 50 to 64 -> next time the for executes it should go 52 to 66 and so on
console.log(copie)
for (i = 0; i < 8; i++) { // the 7 numbers added previously in the one array are getting summed up
totalx += copie[i]
}
rolling_average_delta_follower.push(totalx) // the sum of each array previously created is getting added to the main array where I need the data.
}
All good until I try to actually execute it, I end up with with a forever loop that I seem not to be able to escape.
Any help would be appreciated.
Thank you!

The problem is here:
for (i = 0; i < 8; i++) { // the 7 numbers added previously in the one array are getting summed up
totalx += copie[i]
}
By this code you override i used in the loop above.
Just use another variable name here. (j ?)

To make a copy of an array use the spread operator.
const copy = [...original];
To sum the values of an array use reduce.
const sum = array.reduce((sum, item) => sum + item, 0);

Related

Return only the values if not inside the array in for loop

This array contains 1,5,
let numberArray = [1,5];
I'm trying to print numbers from 1 to 280 except for the values inside the numberArray,
for (let i = 1; i < 281; i++) {
numberArray.forEach((number) => {
if (number != i) {
console.log(i);
}
});
}
I'm expecting the result to be 2,3,4,6,7...280 without printing 1 and 5 in this case. But I get like this,
It prints 2 times each number except 1 and 5. I want to completely omit the values inside the numberArray and print the other values. Really appreciate it if somebody could point me to the bug. Thanks.
It isn't a bug, your code is doing exactly what you are telling it too.
You have your for loop which happens 280 times and then you have a forEach loop inside that which is happening twice every time the loop goes around. So the Foreach loop is actually happening. 558 times.
You can just use the .includes method to check i doesn't exist within the numberArray.
for (let i = 1; i < 281; i++) {
if(!numberArray.includes(i)){
console.log(i);
}
}

Why is this for loop logging correctly, but write to sheet wrongly using GAS?

I'm running this for loop and modifying some values on the go. It logs the values changed correctly in each iteration, but it repeats the last iteration when writing to sheets.
const rngList = cadSheet.getRangeList(dataRng).getRanges();
//Gets the ranges' values and push them into an array;
let values = [];
for (let i = 0; i < rngList.length; i++) {
values = [].concat(values, rngList[i].getValues().flat());
//values.push([rngList[i].getValue()]);
}
let itens = [];
for (let a = 0; a < tamanhosEscArr.length; a++) {
for (let r = 0; r < coresEscArr.length; r++) {
values[4] = variacao++;//Increments an ID number
values.splice(29, 1); //removes this element
values.splice(29, 0, tamanhosEscArr[a]); //inserts size being iterated over
values.splice(30, 1);//removes this element
values.splice(30, 0, coresEscArr[r]); //inserts color being iterated over
Logger.log('Item: ' + values) //logs all 18 or so items, with their corresponding sizes and colors
itens.push(values);
}
}
suporteSheet.getRange(suporteSheet.getLastRow() + 1, 1, itens.length, itens[0].length).setValues(itens); //Writes the last iteration as many times as the iterations (18)
This is the log, showing the correct result:
This is how this is writing to the spreadsheet:
I can't see where the flaw is here, besides my existence.
Thanks for the light!
Try to change:
itens.push(values);
to:
itens.push(values.slice());
Đ•xplanation
Log shows you the current state of the array values at every iteration of the loop. During the next iteration, you change the array values. And all 'previous instances' of the array are changing as well. This is why you're getting the 18 identical arrays. Because all of them are 'references' to the same array values.
If you want to prevent the changes in the 'previous instances' you have to make a copy of current state of the array values and put in the itens this copy. The method array.slice() returns a copy of a given array.

Infinite Loop for finding a power set for a string

I'm working on a problem where I need to find all the power set of a given string which are all the possible subsets. I feel like I'm close with my current code but I can't figure out why I'm getting stuck on an infinite loop for my second iteration. I ran it through the debugger but I still can't seem to figure it out even though I'm sure it's very simple. When i = 0 then it goes to the second loop where j = 0 && j < 1 so for example if help is my given str argument then I would expect it to add j + '' and push it into my allSubsets array. The problem is that the j iteration will keep looping and doing j++ and will never stop. I'm not sure why this is. One particular question even if I solve this infinite loop - do I need to update the allSubsets.length in the iteration to keep it updated with the pushed in strings?
var powerSet = function(str) {
let allSubsets = [''];
for (let i = 0; i < str.length; i++) {
debugger;
for (let j = 0; j < allSubsets.length; j++) {
allSubsets.push(sortLetters(str[i] + allSubsets[j]));
}
}
return allSubsets;
};
var sortLetters = (word => {
//convert string to an array
//use the sort to sort by letter
//convert array back to string and return
return word.split('').sort().join('');
})
Everytime you push to allSubSets, the length increases, and thus, your loop never ends. A declarative loop runs on the range of the initial loop. See below for a fix based on your code:
var powerSet = function(str) {
let allSubsets = [''];
for (let i = 0; i < str.length; i++) {
allSubsets.forEach( (_char, j) => { // declarative loop here
allSubsets.push(sortLetters(str[i] + allSubsets[j]));
})
}
return allSubsets;
};
var sortLetters = (word => {
return word.split('').sort().join('');
})
From MDN web docs:
The range of elements processed by forEach() is set before the first invocation of callback. Elements which are appended to the array after the call to forEach() begins will not be visited by callback. If existing elements of the array are changed or deleted, their value as passed to callback will be the value at the time forEach() visits them; elements that are deleted before being visited are not visited. If elements that are already visited are removed (e.g. using shift()) during the iteration, later elements will be skipped. (See this example, below.)
See the fourth paragraph under descriptions: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach#Description

Unable to pass an array as argument of a javascript function

I'm trying to implement the quickSort algorithm in javascript, i have to extract 10,000 numbers from a txt file, pass them into an array, and pass this as an argument of my quickSort function, using the fs module of nodejs. The code is able to read the 10,000 numbers, and to convert them from an array of string to an array of number, but when i try to pass the array into my function, only 3472 numbers are passed, which i don't understand.
const fs = require('fs');
// Reading the data from the file containing the 10,000 numbers
const file = fs.readFileSync('./quickSort.txt', 'utf-8');
//Checking if it has read all the numbers correctly
console.log(file); // Displays the 10,000 numbers as strings in an array
// Convert them from string to integer
const finalFile = file.split('\n').map(e => {
return parseInt(e, 10);
})
// Checking if it has converted each element of the array to an integer
//console.log(finalFile) displays the array, with the 10,000 elements converted to integers
// Initialize a counter for the comparaisons made by the quickSort algorithm
let comparisons = 0;
// Sort them using quick sort
function quick_Sort(origArray) {
if (origArray.length <= 1) {
return origArray;
} else {
// Checking if the array has been correctly passed as an argument
console.log(origArray.length); //Displays 3742 instead of 10,000
var left = [];
var right = [];
var newArray = [];
var pivot = origArray.pop();
var length = origArray.length;
// I have tried comparisons += length - 1; too, but i doesn't work
comparisons += length;
for (var i = 0; i < length; i++) {
if (origArray[i] <= pivot) {
left.push(origArray[i]);
} else {
right.push(origArray[i]);
}
}
for (var i = 0; i < right.length; i++) {
comparisons++;
if (right[i] < pivot) {
return right.splice(i, 0, pivot);
}
}
return newArray.concat(quick_Sort(left), quick_Sort(right));
}
}
// Display the result
const result = quick_Sort(finalFile);
// expected output: 25
console.log(result);
Thank you very much.
Edit: In fact the problem of the size comes from the last for loop of the function, if i delete it, and insert the pivot between like that, it works (thanks to StardustGogeta) :
return newArray.concat(quick_Sort(left), pivot, quick_Sort(right));
This is a logical error. You need to change
return newArray.concat(quick_Sort(left), quick_Sort(right));
to
return newArray.concat(quick_Sort(left), pivot, quick_Sort(right));
With that change, the program works for me. The problem is that you are accidentally getting rid of (via .pop()) approximately 1/3 of your input values (the pivot values) during sorting.
try this:
const finalFile = file.split('\r?\n').map(.....)
Your parsing code works for me except for one issue: parseInt returns NaN for the last new line so you need to remove the last element from the array like this: finalFile.pop();. However this does not explain why you are seeing such a difference in the number of elements. There must be something different either in the code or the file you posted.

Why doesn't console.log() concatenate strings?

In this example I try to print one asterisk on the first line, two on the second and so on:
var n = 5;
for (i = 0; i < n; i++) {
for (j = 0; j < i; j++) {
console.log('*');
}
console.log('\r\n');
}
The output should look like this:
*
**
***
****
*****
But in the Chrome console I see this:
*
2 *
3 *
4 *
5 *
Why is this?
console.log is not designed to precisely control the rendering of the output. It is a log writer, not a terminal layout API.
It puts each log message on a line of its own, and collapses duplicate, sequential log messages into a single message with a count of the number of times it occurred next to it.
It's doing that because it's how dev tools handles multiple occurrences of the same value for the purposes of clarity.
You can use an array to achieve the effect you're after. Also note that we change j<i to j<= so that it outputs on the 5th.
Then, we use the .join('') method to flatten the array into a string.
Also, since we are console.logging on every iteration loop, a new line will be added automatically as it's one log per loop.
var n = 5;
for (i = 0; i < n; i++) {
var arr = [];
for (j = 0; j <= i; j++) {
arr.push('*');
}
console.log(arr.join(''));
}
Please note that you wouldn't need an array if you were printing this into the DOM - it would work as you originally intended it to do.
Update: Ivar made a great solution as well and that's to use the String.repeat() function which only requires you to use one loop.
var n = 5;
for (i = 1; i <= n; i++) {
var str = '*';
str = str.repeat(i);
console.log(str);
}
Because that's the way it works, basically. Each call to console.log outputs a new log entry. Each log entry is in its own line.
If you log the same string multiple times, they will get summarized into one entry with the count in front.
Don't mistake console.log with Console.Write in C# or similar. It's more like Console.WriteLine.

Categories