For loop not iterating through whole array (Javascript) - javascript

I am trying to solve a problem that takes an array and moves all of the zeros to the end, preserving the order of the other elements.
This isn't iterating through the entire array, any ideas on what I'm doing wrong would be greatly appreciated.
let moveZeros = function (arr) {
let newArr = [];
for (let i = 0; i < arr.length; i++) {
if (arr[i] === 0) {
newArr.push(arr[i]);
arr.splice(i, 1);
}
}
return arr.concat(newArr);
};
moveZeros([9, 0, 9, 1, 2, 1, 1, 3, 1, 9, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0]);
// expexted to return [9,9,1,2,1,1,3,1,9,9,0,0,0,0,0,0,0,0,0,0]
// currently returns [9,9,1,2,1,1,3,1,9,0,9,0,0,0,0,0,0,0,0,0]
// Strangely... sending a smaller array to the function seems to work.
//moveZeros([false,1,0,1,2,0,1,3,"a"])
// correctly returns[false,1,1,2,1,3,"a",0,0]

The problem isn't related to the length, it occurs when you have more than one consecutive 0. For example [0,0,9,0,0,9] will come out [0,9,0,9,0,0].
In the first iteration of the loop (i=0), you remove the first 0 from the array, leaving you with [0,9,0,0,9]. On the second iteration (i=1), it's now looking at the second element in the array, which is 9. The first 0 is skipped. This will happen later in the array too as the loop progresses.
In general it can be problematic to modify an array as you loop through it. There are a number of ways you could perform a sort like this. But to keep it close to your original you could do this:
let moveZeros = function(arr) {
let arrA = [];
let arrB = [];
for (let i = 0; i < arr.length; i++) {
if (arr[i] === 0) {
arrB.push(arr[i]);
} else {
arrA.push(arr[i]);
}
}
return arrA.concat(arrB);
};
Now the function keeps the original array intact as it goes through it. Non-0 items are pushed to arrA, and 0s are pushed to arrB, and then those two are concatenated.

You could keep the array and move all not zero values to the start and fill the rest with zeroes.
let moveZeros = function(array) {
let i = 0,
j = 0;
while (i < array.length) {
if (array[i] !== 0) array[j++] = array[i];
i++;
}
while (j < array.length) array[j++] = 0;
return array;
};
console.log(...moveZeros([9, 0, 9, 1, 2, 1, 1, 3, 1, 9, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0]));
console.log(...moveZeros([false, 1, 0, 1, 2, 0, 1, 3, "a"]));

Related

Strategy for creating N number nested loops in javascript

Suppose I have this pattern:
for(let i =0; i < 3; i++){
for(let j =0; j < 3; j++){
for(let k =0; k < 3; k++){
console.log(i,j,k)
}
}
}
Benefit is I have access to all iteration variables within innermost loop. i, j, and k, disadvantage is it is hardcoded to 3 levels of nested loops. If I want a fourth I need to add that code manually.
I am trying to generalize the code using recursion where I can set the number of nested loops to an arbitrary variable. Here is what I am trying:
const maxNestedLoops = 3;
const iterations = 3;
const indexes = [];
function looper(loopNumber){
for(indexes[loopNumber] = 0; indexes[loopNumber] < iterations; indexes[loopNumber]++){
if(loopNumber < maxNestedLoops){
looper(loopNumber + 1);
}
console.log(indexes);
}
}
looper(0);
The first results in the following in the console:
0, 0, 0
0, 0, 1
0, 0, 2
0, 1, 0
0, 1, 1
0, 1, 2
0, 2, 0
0, 2, 1
0, 2, 2
...and so on
However with my recursive function example it is not the same:
[0, 0, 0, 0]
[0, 0, 0, 1]
[0, 0, 0, 2]
[0, 0, 0, 3]
[0, 0, 1, 0]
[0, 0, 1, 1]
[0, 0, 1, 2]
[0, 0, 1, 3]
[0, 0, 2, 0]
[0, 0, 2, 1]
[0, 0, 2, 2]
[0, 0, 2, 3]
[0, 0, 3, 3]
...and so on
Problems are that not only are there four indexes instead of three. But some of the values are 3s and I would expect it to only go up to 2.
Advice appreciated.
The problem is that:
your console.log should only be executed at the deepest level. So put that console.log in an else clause.
The base case happens when loopNumber === maxNestedLoops - 1 as that is the last index of your array, so the if condition should correspond to that
if (loopNumber < maxNestedLoops - 1){
looper(loopNumber + 1);
} else {
console.log(indexes);
}
There is problem with the for loop. indexes[loopNumber]++ will be increased until it will reach the value of iterations. Since your value of iterations is 3, you will end up with values which are equal to 3 in the indexes array, because the loop itself is modifying the array.
Also, since you modify your array if indexes before checking if the loopNumber reached the number of maxNestedLoops, you will end up with an array with length of maxNestedLoops + 1.
What I suggest you should do:
const maxNestedLoops = 3;
const iterations = 3;
const indexes = [];
function looper(loopNumber) {
// Check if we reached the number of nested loops before doing anything else.
if (loopNumber < maxNestedLoops) {
// Don't modify the indexes array directly, use a variable instead
for (let i = 0; i < iterations; i++) {
indexes[loopNumber] = i;
looper(loopNumber + 1);
console.log(indexes);
}
}
}
looper(0);
Here you go. It was a interesting one :)
const maxNestedLoops = 3;
const iterations = 3;
const indexes = [];
function looper(level){
for (let i=0; i<iterations; i++){
indexes.push(i);
if (level === maxNestedLoops-1) {
console.log(indexes);
indexes.splice(level,1);
continue;
}
looper(level + 1);
indexes.splice(level,1);
}
}
looper(0);

how to write a program to return bfs

I want to write a JavaScript function that takes 3 arguments: an adjacency matrix in the form of a 2D array, number of nodes, and starting vertex.
The function returns the BFS traversal of the graph represented by the adjacency matrix.
function task24(mat,n,v){
let visited=new Array(n)
let queue=[]
let result=[]
while(queue.length!=0){
queue.push(v)
result.push(queue.pop())
for(i=0;i<n;i++){
visited[i]=0
}
let i=v
visited[i]=1
for(j = 0; j < n; j++) {
if(visited[j] == 0 && Adj[i][j] == 1) {
visited[j] = 1;
queue.push(j)
result.push(j)
i=queue.shift()
}
}
}
return result
}
console.log(task24([[0, 1, 0, 0], [0, 1, 1, 1], [1, 0, 0, 1], [0, 0, 1, 0]],4,2))```
Please see comments in code snippet for details. Also you can use a map to replace your visited array, probably it is more efficient if there are some nodes not connected to any other nodes.
function task24(mat,n,v){
const visited=[], queue=[v], result = [];
//start from v and v is already in queue, so visited[v] is 1
visited[v] = 1;
//loop until queue is empty
while(queue.length>0){
//remove the node index from queue using shift and push it result
const curr = queue.shift();
result.push(curr);
//check connected nodes
for(let i = 0; i<mat[curr].length; i++){
//if a node is connected and has not been seen, mark it as seen and push it to queue
if(mat[curr][i] === 1 && !visited[i]){
visited[i] = 1;
queue.push(i)
}
}
}
return result
}
console.log(task24([[0, 1, 0, 0], [0, 1, 1, 1], [1, 0, 0, 1], [0, 0, 1, 0]],4,2))

Splice value from an array and push spliced value into another array

Hello and here is my problem.I have a task,i need to remove elements from an array and push them into another array and then return the array with removed elements. For example, in this case i have to remove all 0 values, and push them into 'a' array and then return 'a' array with there 0 values. I removed 0 values from the array by using splice method and loop, but i don't realy know how to push removed elemts into 'a' array, i've tried to use push method but i does not work for me. Hope you'll help me.Thank you everyone.
function moveZeros(array) {
var a = [];
for (var i = array.length - 1; i--;) {
if (array[i] == "0") {
array.splice(i, 1);
}
}
return a;
}
moveZeros([1, 2, 0, 1, 0, 1, 0, 3, 0, 1]);
Array.splice() returns an array of removed elements, and you can use Array.concat() to add them to the a array.
Notes:
Init i to array.length without the -1, since the condition i--
is checked before the execution of the loop's body.
Since the the array is iterated from end to starts, concat a to the removed
elements to maintain the original order.
function moveZeros(array) {
var a = [];
for (var i = array.length; i--;) {
if (array[i] === 0) {
a = array.splice(i, 1).concat(a);
}
}
return a;
}
var result = moveZeros([1, 2, 0, 1, 0, 1, 0, 3, 0, 1, 0]); // I've added a last 0 to the array to show that all items were removed
console.log(result);
Using push should work. The .splice method will return an array with the removed elements, and you can use the spread operator ... to pass it as a set of arguments to push:
function moveZeros(array) {
var a = [];
for (var i = array.length - 1; i >= 0; i--) {
if (array[i] == "0") {
a.push(...array.splice(i, 1));
}
}
return a;
}
const array = [0, 1, 2, 0, 1, 0, 1, 0, 3, 0, 1, 0, 0];
console.log(moveZeros(array));
console.log(array)
Finally, you should put the i-- as the final part of the loop so that it only executes when each iteration finishes (instead of as they begin). Then, change your condition to be i >= 0 so that you don't miss a zero at the front of the array.
You could iterate from the end and splice the array if necessary. This solution mutates the array.
function moveZeros(array) {
var i = array.length,
a = [];
while (i--) {
if (array[i] === 0) {
a.push(array.splice(i, 1)[0]);
}
}
return a;
}
var array = [1, 2, 0, 1, 0, 1, 0, 3, 0, 1];
console.log(moveZeros(array));
console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Move specified characters in an array

I get a list of elements given as parameter, this is input.
JSON.stringify(moveZeros([1,2,0,1,0,1,0,3,0,1]))
Script should move zeros to the end without changing other elements order.
My solution would looks like this code:
var moveZeros = function (arr) {
var args = Array.prototype.slice.call(arguments);
for(var i=0; i<args.length; i++) {
if (args[i] == 0)
args.splice(i);
args.push(0);
}
console.log(args);
return args;
}
This should append element's with zero value and append a new, 0 value to end of array. It only prints original array without modification.
It is because arguments is all the arguments passed in. You should be using arr and not arguments.
var moveZeros = function (arr) {
var args = arr;
...
}
Also another issue you will face is when you loop from the start to the end and you move elements to the end, you will be skipping indexes as stuff slides down to fill in the hole that you just created. You should be using reduce() or loop from the end to the start if you are using a for loop.
var moveZeros = function(arr) {
var args = arr;
for (var i = args.length - 1; i >= 0; i--) {
if (args[i] === 0) {
args.splice(i, 1);
args.push(0);
}
}
return args;
}
console.log(JSON.stringify(moveZeros([1, 2, 0, 1, 0, 1, 0, 3, 0, 1])));
You could use the copy of arr and use a variable for the length check. If a zero is found, the length variable is decremented and the zero is pushed to the end. If not found, the index is incremented.
var moveZeros = function (arr) {
var args = arr.slice(),
i = 0,
l = args.length;
while (i < l) {
if (args[i] === 0) {
args.push(args.splice(i, 1)[0]);
l--;
} else {
i++;
}
}
return args;
}
console.log(moveZeros([1, 2, 0, 1, 0, 1, 0, 3, 0, 1]));
Or use a loop from the end.
var moveZeros = function (arr) {
var args = arr.slice(),
i = args.length;
while (i--) {
if (args[i] === 0) {
args.push(args.splice(i, 1)[0]);
}
}
return args;
}
console.log(moveZeros([1, 2, 0, 1, 0, 1, 0, 3, 0, 1]));
You had some brackets wrong and missed some arguments. Also you are using an array as the parameter, no need to slice the arguments. You also missed the number of elements for the splice
This does not work for something like [9, 0, 9, 1, 2, 1, 1, 3, 1, 9, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0] (see update further below)
// DOES NOT WORK
var moveZeros = function (arr) {
for (var i = 0; i < arr.length; i++) {
if (arr[i] == 0) {
arr.splice(i, 1);
arr.push(0);
}
}
console.log(arr);
return arr;
}
Working solution
var moveZeros = function(args) {
var r = [];
var zeros = 0;
for (var i = 0; i < args.length; i++) {
if (args[i] !== 0) {
r.push(args[i]);
} else zeros++
}
r = r.concat(Array(zeros).fill(0))
console.log(r);
return args;
}
JSON.stringify(moveZeros([9, 0, 9, 1, 2, 1, 1, 3, 1, 9, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0]));
You have to provide count of values to be removed in splice() method.
Also push 0 only if the value was 0. You are pushing it everytime. (Hint: Because the push statement is not in if).
With a copy of array :
You can maintain a new array and push only non zzero values on to it and later push all the zeros. Simple to understand.
var moveZeros = function(args) {
var arr = [], zCount = 0;
for (var i = 0; i < args.length; i++) {
args[i] == 0 ? zCount++ : arr.push(args[i]);
}
while (zCount-- > 0) arr.push(0);
console.log(arr);
return arr;
}
JSON.stringify(moveZeros([9, 0, 0, 0, 9, 1, 2, 1, 1, 3, 1, 9, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0]));
With reverse loop :
You need a reverse loop because every time when you splice you skip an index so repeated 0s will not be removed.
var moveZeros = function(args) {
for (var i = args.length; i > 0; i--) {
if (args[i] == 0) {
args.splice(i, 1);
args.push(0);
}
}
console.log(args);
return args;
}
JSON.stringify(moveZeros([9, 0, 0, 0, 9, 1, 2, 1, 1, 3, 1, 9, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0]));
I think this would be the funniest way and nicest as line of code and as it's using built-in function (sort) then it faces less performance issues.
var array = [1, 2, 0, -1, 0, 1, 0, 3, 0, 1]
array.sort(a => a === 0);
console.log(array);
first its bad to modify an array while you iterate over it. this can cause some weird jumping that will be confusing.
say you have 1,0,0,1
in your loop when you get to index one it will splice and append the zero to the end of the array
1,0,1,0
but the counter will then increment to 2 and it will miss the 0 which is now at position 1.
It looks like youre trying to create a shallow copy with
var args = Array.prototype.slice.call(arguments);
but I am not really sure.
I wouldn't modify the array you want to return but rather create some temp array and loop through the input, if its 0 up some counter, if its not 0 push it to the holding array, then push on as many 0s as the counter tells you to and return the temp array

Javascript check on array's elements

How can i check an array if its elements are all 0's except one which is 1?
sample:
array = [0, 0, 0, 1, 0];
check(array); //returns the index where it is 1 which is 3
array = [0, 3, 0, 2, 0];
check(array); //returns -1
array = [0, 3, 1, 2, 0];
check(array); //returns -1 again if there are non zero aside from 1, it should be one 1 and others are all 0.
array = [0, 0, 1, 0, 1];
check(array); //returns -1 again, there should just be one element of 1
function check(a) {
var index = -1;
for (var i = 0; i < a.length; i++) {
if (a[i] == 1) {
if (index < 0) {
index = i;
} else {
return -1;
}
} else if (a[i] != 0) {
return -1;
}
}
return index;
}
array1 = [0, 0, 0, 1, 0];
check(array1); //returns 3
array2 = [0, 3, 0, 2, 0];
check(array2); //returns -1
You can use a couple of filters, to generate an array of invalid numbers (i.e. not 0 or 1), and then an array of ones - from the original array. In the end, you can check the lengths of these resultant arrays to see if your criteria is met.
var others = a.filter(function(_item) { return (_item !== 1 && _item !== 0); }),
ones = a.filter(function(_item) { return (_item === 1); });
if(others.length === 0 && ones.length === 1) {
// valid
}
If array elements are guaranteed to be non-negative , then you can sum all elements of array. If sum is anything other than 1, it is not your desired array.
You don't have to loop array elements to calculate sum of elements. Use new reduce function of JavaScript Array. Look it up on web.
Things can get complicated , if array elements can be negative as well.

Categories