Related
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"]));
Without using .indexOf, I'm trying to loop through an array from the end to find the last occurrence of a specific value. This is what I have so far but it keeps returning undefined.
var lastIndexOf = function (array, index) {
for (i=array.length-1; i < 0; i--) {
if (array[i] === index) {
return i;
}
}
}
console.log(lastIndexOf([ 0, 1, 4, 1, 2 ], 1); //should return 3
console.log(lastIndexOf([ 0, 1, 4, 1, 2 ], 2); //should return 4
Yor check is wrong, i is never smaller than zero for an index.
By the way, if you check against a value, you could use the name value instead of index, which leads to wrong assumptions and declare all variables in advance.
var lastIndexOf = function(array, value) {
var i;
for (i = array.length - 1; i >= 0; i--) {
if (array[i] === value) {
return i;
}
}
return -1; // standard default value for not found indices
};
console.log(lastIndexOf([0, 1, 4, 1, 2], 1)); // 3
console.log(lastIndexOf([0, 1, 4, 1, 2], 2)); // 4
console.log(lastIndexOf([0, 1, 4, 1, 2], 42)); // -1
A shorter approach with a while loop.
var lastIndexOf = function(array, value) {
var i = array.length
while (i--) {
if (array[i] === value) {
return i;
}
}
return -1;
};
console.log(lastIndexOf([0, 1, 4, 1, 2], 1)); // 3
console.log(lastIndexOf([0, 1, 4, 1, 2], 2)); // 4
console.log(lastIndexOf([0, 1, 4, 1, 2], 42)); // -1
Your loop condition is wrong. i will never be less than 0 unless the array is empty.
Use this instead:
(i=array.length-1; i >= 0; i--) {
You should change the check you make in the for statement. We start from the last index and we go down to the 0 index. So you loop while index >=0 and not when index<0.
I used different names for some parameters and arguments, in order to make the code more readable.
var lastIndexOf = function (array, number) {
for (var index = array.length-1; index>=0; index--) {
if (array[index] === number) {
return index;
}
}
};
console.log(lastIndexOf([ 0, 1, 4, 1, 2 ], 1)); //should return 3
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
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.
I am trying to sort an array so that all the zeros are at the end. However, I don't want the list to be numerically sorted, all the numbers above zero should stay in the same order. Here's what I've got so far:
function placeZerosAtEnd(arr) {
return arr.sort(compareForSort);
}
function compareForSort(first, second) {
return first == 0 ? 1 : 0;
}
placeZerosAtEnd([9,0,9,1,0,2,0,1,1,0,3,0,1,9,9,0,0,0,0,0]);
This should return [9,9,1,2,1,1,3,1,9,9,0,0,0,0,0,0,0,0,0,0], but actually returns [3,9,9,1,9,2,9,1,1,1,0,0,0,0,0,0,0,0,0,0]. The zeros are correct, but the other numbers are in a strange order. What is going on here?
http://jsfiddle.net/v67fx4zk/
As other have said, using .sort() was wrong in this instance. This is the code I used in the end, as suggested by elclanrs in the comments below my initial post.
function placeZerosAtEnd(arr) {
return arr.filter(isntZero).concat(arr.filter(isZero));
}
function isntZero(element) {
return element > 0;
}
function isZero(element) {
return element == 0;
}
I don't think you can accomplish this with the sort function. Depending on the sort method the browser uses (quicksort, merge sort, etc.), the sort function works by swapping items into place. So there's no telling where the non-zeroes will end up ... your algorithm simply ensures that they'll appear before the 0s.
Here's a function that will accomplish what you're trying:
function placeZerosAtEnd(arr) {
for(var i = 0 ; i < arr.length ; i++) {
if(arr[i]===0) arr.splice(arr.length-1, 0, arr.splice(i, 1)[0]);
}
return arr;
}
The trivial solution with sort: "bubble down" zeros against non-zeros:
[9,0,9,1,0,2,0,1,1,0,3,0,1,9,9,0,0,0,0,0].sort((a, b) => {
if (a !== 0 && b === 0) return -1;
if (a === 0 && b !== 0) return 1;
return 0;
})
// [9, 9, 1, 2, 1, 1, 3, 1, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
you can use this some way too
let listSort = [9, 0, 9, 1, 0, 2, 0, 1, 1, 0, 3, 0, 1, 9, 9, 0, 0, 0, 0, 0],
isntZero = [],
isZero = []
for (let i = 0; i < listSort.length; i++) {
if (listSort[i] == 0)
isZero.push(listSort[i])
else
isntZero.push(listSort[i])
}
let output = isntZero.concat(isZero)
console.log(JSON.stringify(output))
In your example the sort function is doing exactly what it's meant to.
You're expecting a stable sort, but a stable sort is not guaranteed by the javascript sort algorithm.
See this question for a discussion on stable sorting in javascript.
You can use arr.sort to solve this problem
reference:
Array.sort
function placeZerosAtEnd(arr) {
arr.sort(function(key1,key2) {
if (key1 == 0 ) return 1;
return -1;
});
return arr;
}
arr.sort((a,b) => a - b).reverse()