Move specified characters in an array - javascript

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

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);

Split an array when meets a certain number?

Hello I need to return count of chunks in given array of numbers.
Chunk can be defined assequence of one or more numbers separated by one or more zeroes.
Example: array [5, 4, 0, 0, -1, 0, 2, 0, 0] contains 3 chunks
so the answer should be 3 since the array can be split into three chunks.
Can you help me with the solution to this one?
Ive looped through the array but dont know how to deal with the multiple zeros.
In case you're interested in a good-performance, concise solution, in a single iteration...
Here's one based on iter-ops library:
import {pipe, count, filter, split} from 'iter-ops';
const data = [5, 4, 0, 0, -1, 0, 2, 0, 0];
const c = pipe(
data,
split(v => v === 0), // split into chunks, by zero
filter(a => !!a.length), // ignore empty chunks
count() // count resulting chunks
).first; // take the first value (our count)
console.log(c); //=> 3
P.S. I'm the author of the library.
You could add a flag for keeping track of counting the actual chunk and rest it only by fing a zero.
let data = [5, 4, 0, 0, -1, 0, 2, 0, 0],
count = 0,
lastCount = false;
for (const value of data) {
if (value === 0) {
lastCount = false;
continue;
}
if (!lastCount) {
count++;
lastCount = true;
}
}
console.log(count);
If you needed to keep track of the chunks as well you can loop it using a simple for loop like so:
var arr = [5, 4, 0, 0, -1, 0, 2, 0, 0];
var chunks = [];
for(var i = 0; i < arr.length; i++){
if(arr[i] !== 0){ // check that the current number isn't a 0
if(arr[i - 1] === 0 || arr[i - 1] === undefined){ // check if previous number was a 0
chunks.push([]); // add a new chunk if previous number was a 0
}
chunks[chunks.length - 1].push(arr[i]); // push the number to latest chunk
}
}
//console.log(chunks);
console.log("There are " + chunks.length + " chunks");
A simple solution leveraging the second parameter of indexOf() within a while loop.
function count_chunks(arr, delimeter = 0) {
let count = 0, lastIndex = 0, index = 0;
while (index !== -1 && lastIndex < arr.length) {
index = arr.indexOf(delimeter, lastIndex);
if (index - lastIndex) {
count++;
}
lastIndex = index + 1;
}
return count;
}
const data = [5, 4, 0, 0, -1, 0, 2, 0, 0];
console.log(count_chunks(data));
// leading zero
console.log(count_chunks([0, 5, 4, 0, 0, -1, 0, 2]));
// no head or tail delimeters
console.log(count_chunks([5, 4, 0, 0, -1, 0, 2]));
// different delimeter
console.log(count_chunks([5, 4, 'x', 'x', -1, 'x', 2, 'x', 'x'], 'x'));
You can solve it by using Regular expressions.
let array = [5, 4, 0, 0, -1, 0, 2, 0, 0];
let arrayToString = array.join("").toString();
let occurrenceRegex = /0+/g; // Regex that will check for one or more occurrences
let result = arrayToString.match(occurrenceRegex).length;
console.log(result); // Output: 3

For loop not iterating through whole array (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"]));

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; }

Javascript - Creating pyramid array from number values

I am looking to create a pyramid array from number values. The requirement is that I am to work from an array that which in my case has 3 rows with 5 columns. I need to create a pyramid that looks like the example below.
Here is what I want to achieve exactly..
[0, 0, 1, 0, 0]
[0, 1, 1, 1, 0]
[1, 1, 1, 1, 1]
So far my code looks something like this..
var a = [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]];
function array_pyramid( array ){
for (i = 0; i < array.length; i++){
for (j = 0; j <= Math.floor(array[i].length / 2); j++){
var tmp = array[i].length / 2;
console.log (Math.floor(tmp));
if ( i < j ) {
array[i][j] = 1;
}
}
}
return array;
}
function print_array(array) {
for (var i = 0; i < array.length; i++) {
console.log(array[i]);
}
}
//console.log(a);
//print_array(a);
print_array(array_pyramid(a));
Try example below. I purposely kept variable names long and descriptive and kept operations in multiple steps rather than inline for the ease of analyzing.
var a = [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]];
function array_pyramid(array){
var pBlocksCount = 1;
var currentRow, rowIndex, columnIndex, columnsCount, rowsCount = array.length;
for(rowIndex=0; rowIndex<rowsCount; rowIndex++){
currentRow = array[rowIndex];
columnsCount = currentRow.length;
var piramidDrawIndex = parseInt(columnsCount/2);
var piramidDrawOffset = parseInt(pBlocksCount/2);
var piramidDrawTrigger = piramidDrawIndex-piramidDrawOffset;
var blocksToDraw = pBlocksCount;
for(columnIndex=0; columnIndex<columnsCount; columnIndex++){
if(columnIndex>=piramidDrawTrigger){
if(blocksToDraw){
currentRow[columnIndex]=1;
blocksToDraw--;
}
}
}
pBlocksCount+=2;
}
return array;
}
function print_array(array) {
for (var i = 0; i < array.length; i++) {
console.log(array[i]);
}
}
print_array(array_pyramid(a));
This will probably fail for most other cases you could come up with, but works in this specific instance:
function array_pyramid( array ){
var mid = Math.floor(array[0].length/2);
for(var i=0;i<array.length;i++){
for(var j=0;j<array[i].length;j++){
var boundsLower = mid-i;
var boundsUpper = mid+i;
if(j>=boundsLower && j<=boundsUpper){
array[i][j] = 1;
}
}
}
return array;
}
Live example: https://jsfiddle.net/o6t1cbdu/
Try this ...
function array_pyramid(array){
var limit = [0,0];
for (var i = array.length - 1, limit = [0, (array[0] || []).length - 1]; i >= 0; i--) {
for (var j = limit[0]; j <= limit[1]; j++) {
array[i][j] = 1;
}
limit[0]++; limit[1]--;
}
return array;
}
I hope it helps
You were starting down the right track with an inner and an outer loop, as well as your use of division to try to account for the midpoint.
Here is a verbose and heavily commented modification of your code that accounts for any number of columns (odd or even) and uses a range that widens during row progression to determine which columns should be 1 or 0. I've included a second array, b, to show it works for even column counts as well.
var a = [
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0]
],
b = [
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0]
];
function array_pyramid (a) {
// Use first row to determine row length, assume all others are the same
var base_length = a[0].length,
// Get a modulus to account for odd or even row length
mod = base_length % 2,
// Find the middle point
mid_point = Math.floor(base_length / 2) + mod,
// Account for zero-index of arrays
zero_indexed = mid_point - 1,
// Produce an initial set of boundaries
marker_range = {
lower: zero_indexed,
upper: (mod === 1) ? zero_indexed : (zero_indexed + 1)
};
// Iterate the array's rows
a.forEach(function (row) {
// Iterate the row's cols
row.forEach(function (col, i) {
// Compare index to boundaries to determine if we're outputting a 1 or a 0
row[i] = (i >= marker_range.lower && i <= marker_range.upper) ? 1 : 0;
});
// If we still have room to expand, widen the range in each direction
if (marker_range.lower > 0) {
marker_range.lower -= 1;
marker_range.upper += 1;
}
});
return a;
}
function print_array(a) {
var i;
console.log('-- Start output');
for (i = 0; i < a.length; i++) {
console.log(' ', a[i]);
}
console.log('-- End output');
console.log(' ');
}
console.log('a (odd col count):');
print_array(array_pyramid(a));
console.log('b: (even col count)');
print_array(array_pyramid(b));
So here is my code, it works fine.
The idea is that you find the main vertical center of the matrix and the sideA and sideB variables represent the left and the right side of the pyramid. Once you've found the sides, you make them equal to one as well as everything between them ( if (j <= sideA && j >= sideB) ). I hope that helps. :)
function array_pyramid ( array ) {
var item, sideA, sideB;
if (array instanceof Array) {
for (var i = 0; i < array.length; i++) {
item = array[i];
centerIndex = Math.floor(item.length / 2);
sideA = centerIndex + i;
sideB = centerIndex - i;
for (var j = 0; j < item.length; j++) {
if (j <= sideA && j >= sideB) {
item[j] = 1;
}
}
}
return array;
} else {
return 'Invalid array';
}
}
array_pyramid ([
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
]);
When you run that code in the console it will return this:
[0, 0, 1, 0, 0]
[0, 1, 1, 1, 0]
[1, 1, 1, 1, 1]
And that's it.

Categories