Using splice to delete item in array - javascript

Why does the remaining in original array = [1, 3, 5, 7, 9]
Since arr.splice(i, 1) = i is the target index and 1 is the number of item to be removed, i is increases to 10 respectively from i++ which short for i = i + 1, So why does it remove 5 index and remain 5 in the array ? that's what i know so far and i have struggled to read the docs but still have no idea to understand, please explain it for me
let arr = [1,2,3,4,5,6,7,8,9,10];
for(let i = 1; i < arr.length; i++) {
arr.splice(i, 1);
}

It is because the length of arr decreases everytime splice function runs.
Here is how the array changes.
[2, 3, 4, 5, 6, 7, 8, 9, 10]
[2, 4, 5, 6, 7, 8, 9, 10]
[2, 4, 6, 7, 8, 9, 10]
[2, 4, 6, 8, 9, 10]
[2, 4, 6, 8, 10]
So every loop, i increases and arr.length decreases by 1. so only 5 loops runs and the result is [2, 4, 6, 8, 10]

You're wondering why it's removing 1, 3, 5, 7, and 9, right?
Here's why. As the for loop iterates, i keeps increasing by one.
HOWEVER, by calling .splice, you are removing the first element of the array, so as a result, every other element moves down an index.
Let's play this out step by step for a few iterations of the for loop.
i = 0; arr.splice(0, 1) removes 1, so arr is [2, 3, 4, 5, 6, 7, 8, 9, 10]
i = 1; arr.splice(1, 1) removes 3, not 2, because now 3 is at index 1 of arr. Performing the splice leaves arr as [2, 4, 5, 6, 7, 8, 9, 10].
i = 2; arr.splice(2, 1) removes 5, because 5 is currently at index 2. As a result, arr becomes [2, 4, 6, 7, 8, 9, 10].
Is it clear now what's going on?
If your goal is to successively remove each element, one at a time, then instead of calling .splice(i, 1) in each iteration of the loop, you should call .splice(0, 1), since the value at index 0 changes each time you call .splice.

Remember, arrays are 0 based. Second, the length is changing each time it evaluates.
MDN links:
Splice
Map
So you may want to try
i =< length
Where length is determined and is set ahead of time and constant. You can try mapping the array to a new one, so the original array stays pure and unaffected by the splice.

You need to check the for loop end condition, i is not increasing to 10. Why? because i < arr.length.
So it will like this :
Iteration 1:
i=0; arr.length = 10; arr = [1,2,3,4,5,6,7,8,9,10]; ==> result [2,3,4,5,6,7,8,9,10];
Iteration 2:
i=1; arr.length = 9; arr = [2,3,4,5,6,7,8,9,10]; ==> result [2,4,5,6,7,8,9,10];
Iteration 3:
i=2; arr.length = 8; arr = [2,4,5,6,7,8,9,10]; ==> result [2,4,6,7,8,9,10];
.
.
.and so forth
i = 5 ==> arr.length: 5 ==> final result : [2, 4, 6, 8, 10]
So if you want to delete all items using splice:
let arr = [1,2,3,4,5,6,7,8,9,10];
while(arr.length > 0) {
arr.splice(0, 1);
}

Related

Cumulative total with restart upon reaching a limit with a condition (part2)

Here is the link to a similar question I asked previously. This time I want to change the conditions. Here is the details:
I have an array:
inputArr = [2, 4, 3, 7, 8, 2, 3, 4, 9, 1];
All the numbers are below '10'. I want the cumulative total of the numbers pushed to the output array. But with two conditions:
if the cumulative total is not equal to '10' but closest to '10', after reaching the cumulative total closest to (not exceeding) '10', calculate the difference to '10' and push the difference as another element to the output array right after the last number that makes cumulative total to be closest to '10'.
AND restart pushing the cumulative total to output array from next number in the input array.
So, the output should be:
outputArr = [2, 6, 9, 1, 7, 3, 8, 2, 3, 4, 3, 9, 1];
Step by step explanation of how this output array is created:
I have tried modifying this code. Here is the modified code:
let input = [2, 4, 3, 7, 8, 2, 3, 4, 9, 1],
output = [],
cumulative = 0;
for (let i = 0; i < input.length; i++) {
cumulative += input[i];
if (cumulative < 10) {
output.push(cumulative)
} else if (cumulative == 10) {
output.push(10)
cumulative = 0
} else {
output.push(10 - output[i - 1])
cumulative = input[i]
output.push(cumulative)
}
}
console.log(output)
This code gives me this output:
outputArr = [2, 6, 9, 1, 7, 9, 8, 10, 3, 7, 0, 9, 10]
Here, only first 4 elements in the output array came as intended. How can I correct this code?
Any help is much appreciated.

Loop backwards Javascript Array

I would like to loop backwards in a array in javascript and then get the index of each element in the array for example if a array has 10 elements and is looped backwards it would log 9, 8, 7, 6, 5, 4, 3, 2, 1, 0. for some werid reason i am getting a bunch of negaitive -1s and im confused why it wont just return the index properly.
here is the code
//Arrays I would like to pass into the function
const valid1 = [4, 5, 3, 9, 6, 7, 7, 9, 0, 8, 0, 1, 6, 8, 0, 8];
const invalid1 = [4, 5, 3, 2, 7, 7, 8, 7, 7, 1, 0, 9, 1, 7, 9, 5];
function validateCred(arr) {
let sum = 0;
for (let i = arr.length - 1; i >= 0; i--) {
console.log(arr.indexOf(i));
}
}
console.log(validateCred(valid1));
why -1s?
It is because of arr.indexOf(i) when the loop starts i=15 so:
arr.indexOf(15) will return -1 because you don't have a 15 in your array.
next i=14 same as above.
.
.
.
i=9 then it will find the element at index 3.
As UnholySheep explains above, Array.indexOf(i) gives you the index of the first occurrence of the value represented by i in the array. Here is some code to help you debug:
function validateCred(arr) {
let sum = 0
for (let i = arr.length - 1; i >= 0; i--) {
console.log(i) // log the index
console.log(arr[i]) // log the value
}
}

Looping over the last few entries of an array

I'm trying to have a forEach loop over an array, but only the last few entries.
I'd know how to do this in a for loop, that'd look a bit like this:
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
/* This will loop over the last 3 entries */
for(var x = arr.length; x >= 7; x--){
console.log(arr[x]);
}
Would there be any way of achieving the same results in a forEach loop?
You can use slice() and reverse() methods and then forEach() loop on that new array.
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
arr.slice(-3).reverse().forEach(e => console.log(e))
This is how you do it with forEach loop:
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
arr.forEach((element, index) => {
if(index>7) console.log(arr[index]);
})
You could take a classic approach by taking the count of the last elements and use it as counter and an offset for the index.
Then loop with while by decrementing and checking the counter.
var array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
last = 3,
offset = array.length - last;
while (last--) {
console.log(array[last + offset]);
}

javascript, forEach and removeChild unpredictable behavior

I wish to remove all items from a list and replace them with others
var list = document.querySelector("ul");
[].forEach.call(list.childNodes, list.removeChild.bind(list));
The code above does not work as expected, instead it removes only half the items (leaving every second item in the list).
If i change it to
var list = document.querySelector("ul");
[].slice.call(list.childNodes).forEach(list.removeChild.bind(list));
Then it works as expected,
can anyone explain ?
In the first one you are mutating an array you are iterating over.
In the second you are making a copy and then iterating over it.
The following is another option that doesn't require making a copy:
for(; list.firstChild; list.removeChild(list.firstChild));
This removes the firstChild while it is not null.
Concept
To explain the "unpredictable" behavior in the first scenario, consider this case:
var array = [0, 1, 2, 3, 4, 5, 6, 7];
This makes the behavior easier to explain without the distracting .call() and .bind() methods to wrap your head around.
array.forEach(function(num, index) {
console.log(num, index);
array.splice(index, 1);
});
You may be wondering why the output is:
0 0
2 1
4 2
6 3
But it's actually really simple. .forEach() iterates over the indices until i < array.length is no longer satisfied, while at the beginning of each iteration, your array looks like this:
[0, 1, 2, 3, 4, 5, 6, 7];
^
0
[1, 2, 3, 4, 5, 6, 7];
^
1
[1, 3, 4, 5, 6, 7];
^
2
[1, 3, 5, 6, 7];
^
3
[1, 3, 5, 7];
^
(4 < array.length) !== true
This is what happens when you manipulate an array being iterated over within a call to .forEach().
For the case where you execute [].slice.call(array), all you're doing is making a shallow copy of all the indices of the array. This allows you to iterate over the copy's indices while removing the nodes from the original.
Below is a comprehensive example, but make sure your browser supports ES6 template strings.
Demo
var array = [0, 1, 2, 3, 4, 5, 6, 7];
document.write(`<p>original.forEach()</p>`);
array.forEach(function(num, index) {
document.write(`<pre>num: ${num}, index: ${index}, array: [${array}]</pre>`);
array.splice(index, 1);
});
document.write(`<pre>result: [${array}]</pre>`);
array = [0, 1, 2, 3, 4, 5, 6, 7];
var copy = array.slice();
document.write(`<p>copy.forEach()</p>`);
copy.forEach(function(num, index) {
document.write(`<pre>num: ${num}, index: ${index}, array: [${array}]</pre>`);
array.splice(array.indexOf(num), 1); // removing by reference, not by index
});
document.write(`<pre>result: [${array}]</pre>`);
body > * {
padding: 0;
margin: 0;
}

lodash : how to loop with between a start value and end value

I've a for loop in javascript shown below. How to convert it to lodash for loop?
In such scenarios using lodash is advantageous over javascript for loop?
I've not used lodash much. Hence please advice.
for (var start = b, i = 0; start < end; ++i, ++start) {
// code goes here
}
You can use lodash range
https://lodash.com/docs/4.17.4#range
_.range(5, 10).forEach((current, index, range) => {
console.log(current, index, range)
})
// 5, 0, [5, 6, 7, 8, 9, 10]
// 6, 1, [5, 6, 7, 8, 9, 10]
// 7, 2, [5, 6, 7, 8, 9, 10]
// 8, 3, [5, 6, 7, 8, 9, 10]
// 9, 4, [5, 6, 7, 8, 9, 10]
// 10, 5, [5, 6, 7, 8, 9, 10]
I will imagine that b = 3 and end = 10 if I run your code and print the variables here is what I will get:
var b = 3;
var end = 10;
for (var start = b, i = 0; start < end; ++i, ++start) {
console.log(start, i);
}
> 3 0
> 4 1
> 5 2
> 6 3
> 7 4
> 8 5
> 9 6
To perform this with lodash (or underscore) I will first generate an array with range then iterate over it and gets the index on each iteration.
Here is the result
var b = 3;
var end = 10;
// this will generate an array [ 3, 4, 5, 6, 7, 8, 9 ]
var array = _.range(b, end);
// now I iterate over it
_.each(array, function (value, key) {
console.log(value, key);
});
And you will get the same result. The complexity is the same as the previous one (so no performance issue).
It seems there is no lodash way for writing loose for loops (those not iterating over a collection), but here is a simplified version of it:
for (var i = 0; i < end - b; i++) {
var start = i + b;
// code goes here
}

Categories

Resources