Why this foreach loop not popping all the elements? - javascript

its only popping twice rather than 4 times
i tried for of loop but still same result.
var arr = [1, 2, 3, 4];
arr.forEach((val, index, io) => console.log(val, index, io.pop()))

Your code works as expected.
Array.pop() method removes the last element from an array and returns that element. This method changes the array from which it has been called.
Array.pop() returns the removed element from the array.
When the iteration index is 0, it will iterate through the array [1, 2, 3, 4], it removes 4 on the first iteration, which makes the length of the array as 3.
When the iteration index is 1, iteration will be done on Array [1, 2, 3] and it removes 3 from this array.
Now the length of Array is 2 and the iteration has already completed twice and the loop exits.
Thats why your loop excecutes only twice.
const arr = [1, 2, 3, 4];
arr.forEach((val, index, io) => {
console.log(`Iterating ${index + 1}`);
console.log(val, index, io.pop());
console.log(`Array After Iteration ${io}`);
});
console.log(`Final Array ${arr}`);

var arr = [1, 2, 3, 4];
arr.forEach((val, index, io) => console.log(val, index, io.pop()))
Your code is doing what it should
val | index | io.pop() | Modified Array
1 0 4 [1, 2, 3]
2 1 3 [1, 2]
// since it already reached at 2 no other element needs to be traversed and hence iteration stops.
Each time you are logging it is removing the last element of the array and moving the forward as well.
The callback is executed only for the elements that are present in the array and hence as your elements are being removed with every log you remain with two elements and hence it runs only two times.
Hope This helps. !✌

Related

Does 'array[array.length - 1] = array.pop()' yield undefined behavior?

I've been trying to implement a method which takes an array and an index as input, copies the last element of the given array into the entry at the given index, and then truncates the last element (i.e., sets the array shorter by one).
Here is the function which I was given as a suggestion for this task:
function swapWithLastAndRemove(array, index) {
array[index] = array.pop();
}
I then tested this function to make sure that it works on any given index:
for (let index = 0; index < 5; index++) {
var array = [0, 1, 2, 3, 4];
swapWithLastAndRemove(array, index);
console.log(array);
}
And I found it that it works correctly for all but the last index:
[ 4, 1, 2, 3 ]
[ 0, 4, 2, 3 ]
[ 0, 1, 4, 3 ]
[ 0, 1, 2, 4 ]
[ 0, 1, 2, 3, 4 ]
In other words, for the last element, it pops it out of the array, but then rewrites it into the array.
What strikes me, is that this line:
array[index] = array.pop();
Which is equivalent to this line when executed on the last element:
array[array.length - 1] = array.pop();
Could not have possibly resulted with the contents of array being equal to [ 0, 1, 2, 3, 4 ].
The way I see it, there are two options here:
The statement array.pop() is executed before the expression array.length - 1 is evaluated
The statement array.pop() is executed after the expression array.length - 1 is evaluated
In the first case, the contents of array would change as follows:
[ 0, 1, 2, 3, 4 ] // initial state
[ 0, 1, 2, 3 ] // after popping 4
[ 0, 1, 2, 4 ] // after assignment
In the second case, it should have triggered some sort of memory-access violation, because there would be an attempt to write into the 5th entry in the array (array[4]), when the length of the array is only 4 entries.
I know that NodeJS could be applying some memory-management scheme which would somehow allow this to complete without an "array index out of bound" exception, but I still don't get why it would let this operation "get away with it", and moreover, why the result is what it is.
Is the line array[array.length - 1] = array.pop() possibly undefined behavior?
Is there even such thing as undefined behavior in JavaScript?
The second option: The statement array.pop() is executed after the expression
array.length - 1 is evaluated
This is indeed what happens. JS evaluation is always left-to-right. It evaluates the array.length - 1 to index 4 of the array, then pops the last element from the array, then assigns that element to index 4.
In the second case, it should have triggered some sort of memory-access violation, because there would be an attempt to write into the 5th entry in the array (array[4]), when the length of the array is only 4 entries.
No, there are no memory access violations in JS. It just creates a new property again, and changes the length of the array accordingly. It's just the same as what happens with the code
const array = [0, 1, 2, 3, 4];
const element = array.pop();
console.log(JSON.stringify(array)); // [0,1,2,3]
array[4] = element;
console.log(JSON.stringify(array)); // [0,1,2,3,4]
Similarly, filling an array uses the same feature:
const array = [];
for (let i=0; i<5; i++)
array[i] = i; // no memory access violation
console.log(array.length); // 5
The last index results in [0, 1, 2, 3, <empty>, 4], not [ 0, 1, 2, 3, 4 ]:
function swapWithLastAndRemove(array, index) {
array[index] = array.pop();
}
var array = [0, 1, 2, 3, 4];
swapWithLastAndRemove(array, 5);
console.log(array);
Execution order isn't really something to worry about here, because the index is constant - the parameter index is never reassigned, so the number passed into swapWithLastAndRemove will always be the index, which the popped item is assigned to. Considering it introduces more confusion than necessary - easier to just keep in mind that the passed index is never reassigned.
What's going on is:
(1) The last item of the array is popped off (4), resulting in the array becoming [0, 1, 2, 3]
(2) The index passed in was 5, so array[5] is set to 4. The operation is equivalent to:
const arr = [0, 1, 2, 3];
arr[5] = 4;
console.log(arr);
This is resulting in a sparse array - there's no item at index 4 anymore. It's not undefined behavior, it's just weird, because sparse arrays are weird.
Is there even such thing as undefined behavior in Javascript?
Yes, see here.

forEach seems to be working for push() function but didn't work for pop() in JavaScript. can someone tell me what I am doing wrong

//code1
let a= [1, 3 , 4, 6];
[7, 8 , 9].forEach(l => a.push(l));
console.log(a);
// [1, 3, 4, 6, 7, 8, 9 ]
1.it worked for push() function
//code2
let a= [1, 3 , 4, 6];
a.forEach(l => a.pop(l));
console.log(a);
//[ 1, 3 ]
2. didn't work for pop() though
Javascript Array.pop() removes the last element from the array and returns that.
Example:
var arr = [1,2,3]
arr.pop(); // returns 3
Reference
If you want to remove a element with specific value than try something like:
var arr = [1, 2, 3];
var index = arr.indexOf(1);
if (index > -1) {
array.splice(index, 1);
}
var arr = [1, 2, 3, 4];
console.log(arr.pop());
var index = arr.indexOf(2);
if (index > -1) {
arr.splice(index, 1);
}
console.log(arr)
forEach automatically extracts the elements one by one and gives them to you
It starts from the beginning of the array, and does them all.
It doesn't delete elements from the array.
a = [1, 3, 4, 6];
a.forEach(item => console.log(item));
// output is in forwards order
// and 'a' retains original contents
pop() extracts and deletes one element for you
It starts from the end of the array, and does only one.
It deletes the element from the array.
a = [1, 3, 4, 6];
while (a.length > 0) {
console.log(a.pop())
}
// items come out in reverse order
// and 'a' is being emptied so it is [] at the end
Choose your method
Do you want the last element actually removed from the array? This is what you would want if you were implementing a stack, for example. In that case, use ".pop()".
This gets one element from the end of the array and deletes it from the array.
Or do you want to just look at each element in turn from the array (starting at the beginning), without changing the array itself. This is a commoner situation. In this case, use ".forEach"

group items in array in javascript

I have an array of items, can be objects with many properties, and I want to group some of these items based on order:
example:
[a,b,c,d,e] => [a,[b,c,d],e]
must group (b, c, d) or (a) or (b, c) or (all)
must not group (a, c) or (a, d) for example because they are not sequential
Some possibilites:
[a,b,c,d] to [[a,b,c,d]]
[a,b,c,d] to [[a],b,c,d]
[a,b,c,d] to [[a,b],c,d]
[a,b,c,d] to [[a,b,c],d]
[a,b,c,d] to [a,b,[c,d]]
always sequential items
think of item a like an object with index;
If I understand correctly, you want to group n sequential elements of the array starting from an index ind and put that that group back into the array at the same index. You can acheive that using splice:
function group(arr, ind, n) {
var g = arr.splice(ind, n); // cut out n elements from the array at index ind
arr.splice(ind, 0, g); // push back those cut-out elements into the same index ind (the elements are in array because of the first slpice call)
}
var arr = [1, 2, 3, 4, 5, 6];
group(arr, 2, 3);
console.log(arr); // [1, 2, [3, 4, 5], 6]
EDIT:
As requested, changing group to create a new array instead of altering the original and taking start and end indexes. So for that we are going to use slice/concat instead of splice:
function group(arr, start, end) {
return [].concat(arr.slice(0, start), [arr.slice(start, end + 1)], arr.slice(end + 1));
}
var arr = [1, 2, 3, 4, 5, 6];
console.log(group(arr, 2, 3)); // => [1, 2, [3, 4, 5], 6]
console.log(group(arr, 4, 6)); // => [1, 2, 3, 4, [5, 6]]
console.log(group(arr, 0, 3)); // => [[1, 2, 3, 4], 5, 6]
which concatinate the subarrays: from 0 to start, from start to end + 1 (put in an array of its own so its stays grouped) and from end + 1 onward. If you want the end index to be exclusive (the element at end not included) then just change end + 1 to end.
Based on the more recent comments you may be looking for Array's own, built-in slice method, it provides a continuous sub-region of an array, where start and end positions are its arguments:
function format(a){return "["+a.join(",")+"]";}
var arr=['a','b','c','d','e'];
console.log("original: "+format(arr));
console.log("slice(0,1): "+format(arr.slice(0,1)));
console.log("slice(0,2): "+format(arr.slice(0,2)));
console.log("slice(1,4): "+format(arr.slice(1,4)));
console.log("slice(2,4): "+format(arr.slice(2,4)));
console.log("slice(2,2): "+format(arr.slice(2,2)));
Note 1: The second argument is the position of the "last+1" element you want, it is best seen in the last example where slice(2,2) provides an empty array
Note 2: format is just about getting array contents in one line, console.log(somearray) displays the elements vertically.
Then of course you can do whatever you need, but it is definitely worth to note that this function exists and it is built-in.
Like building the array-in-array thing you describe:
function format(a){var s="[",first=true;a.forEach(function(i){
if(first)first=false;else s+=",";s+=i instanceof Array?format(i):i;});
s+="]";return s;}
function group(arr,begin,end){
var ret=[];
for(var i=0;i<begin;i++)ret.push(arr[i]);
ret.push(arr.slice(begin,end));
for(var i=end;i<arr.length;i++)ret.push(arr[i]);
return ret;
}
var arr=['a','b','c','d','e'];
console.log("original: "+format(arr));
console.log("group(arr,0,1): "+format(group(arr,0,1)));
console.log("group(arr,0,2): "+format(group(arr,0,2)));
console.log("group(arr,1,4): "+format(group(arr,1,4)));
console.log("group(arr,2,4): "+format(group(arr,2,4)));
console.log("group(arr,2,2): "+format(group(arr,2,2)));
Examples are the same as for the slice-explanation, including the empty array in the last one (with 2,2). It is up to you if you want such empty element (as kind of a 'cursor') or not.
And of course the thing also works with the nested loops in my original answer, if you want to generate all possible selections from an array - that is how your question initially seemed to me:
function format(a){var s="[",first=true;a.forEach(function(i){
if(first)first=false;else s+=",";s+=i instanceof Array?format(i):i;});
s+="]";return s;}
function group(arr,begin,end){
var ret=[];
for(var i=0;i<begin;i++)ret.push(arr[i]);
ret.push(arr.slice(begin,end));
for(var i=end;i<arr.length;i++)ret.push(arr[i]);
return ret;
}
var arr=['a','b','c','d','e'];
console.log("original: "+format(arr));
for(var i=0;i<arr.length;i++)
for(var j=i+1;j<=arr.length;j++){
console.log(format(group(arr,i,j)));
}

How to remove an item from a list without distorting the original list

This is what I'm trying to do, I have an array
var arr = [1, 2, 3, 4, 5];
then I want to create a new array each time by removing an item once i.e when i remove item at index 0 i should have [2, 3, 4, 5]and when i remove an item at index 1, I should have [1, 3, 4, 5] and so on till i get to arr.length-1 and each time i remove an item i still want my arr to be intact unchanged
using javaScript I have tried some array methods like splice, slice but all that changes the value of arr
how do i go about it with either javascript or python.
For Javascript, using ES6 array spread operator and slice method,
var new_array = [...a.slice(0, index), ...a.slice(index + 1)];
const cut = (a, i) => [...a.slice(0, i), ...a.slice(i + 1)];
let arr = [2, 2, 2, 4, 2];
console.log(cut(arr, 3));
console.log(arr);
For Python:
array = [1,2,3,4,5];
newarray = [value for counter, value in enumerate(array) if counter != 0 ]
PS each time you will use this list-comprehension, array will not be modified! so basically you will get the same output for newarray.
If you want to have newarray each time removed one element you need to create a function instead of list-comprehension (of course it's possible but will likely be less readable).
For JavaScript:
Try making a copy with slice() (slice returns a shallow copy of the array that you can manipulate without affecting the original array) and then using splice() to remove the value at your desired index:
newArray = slice(arr).splice(index, 1);

Iteratively adding up first and last numbers in an array

I'm trying to write a function that continually adds together the first and last elements of an array using forEach with array.shift() + array.pop().
The problem is that the for-loop doesn't complete the innermost numbers, and so the array is always left with 2 values inside of it.
Code:
function choreAssignment(chores) {
chores.sort(function(a, b) {return a - b});
var assignment = [];
chores.forEach(function() {
assignment.push((chores.pop() + chores.shift()));
});
return assignment.sort(function(a, b) {return a - b});
}
The above code works as expected, but it leaves the innermost two values inside the chores array.
For example if I run:
Code:
var arr = [1, 4, 7, 2, 5, 9, 4, 3];
choreAssignment(arr);
I get:
[8, 9, 10]
Ie, it adds 9 & 1, 7 & 2, 5 & 3, but it leaves [4, 4] inside the array.
I'm not sure why this is. Thank you.
Try changing the forEach to:
while (chores.length) {
assignment.push((chores.pop() + chores.shift()));
}
Note this assumes there are always an even number of elements in array

Categories

Resources