Javascript - Creating pyramid array from number values - javascript

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.

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

Finding the first index of a sequence inside an array

In this function I count the number of consecutive zeros that should be at least of length zerosMin. Is there any way I could return the first index of the start of the sequences? For example, for arr = [1,0,0,0,0,0,1,0,0,0,0] it would be [1,7]
function SmallestBlockOfZeros(arr, zerosMin) {
let result = [];
let counter = 1;
for (let i = 0; i < arr.length; i++) {
if (arr[i] == 0) {
if (arr[i] === arr[i + 1]) {
counter++;
} else if (counter >= zerosMin) {
result.push(counter);
counter = 1;
} else {
counter = 1;
}
}
}
return result;
}
let arr = [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0];
let zerosMin = 4;
console.log(SmallestBlockOfZeros(arr, zerosMin));
//Console output : [5,4]
You can iterate through the array, pushing an index into the result array whenever you encounter a block of 0 values that is at least zerosMin long, and then skipping all those 0 values until you find the next non-0 value or pass the point at which a zerosMin string of 0s could occur:
let arr = [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0];
let zerosMin = 4;
let zeroStarts = [];
for (let i = 0; i <= arr.length - zerosMin; i++) {
if (arr.slice(i, i + zerosMin).filter(Boolean).length == 0) {
zeroStarts.push(i);
i += zerosMin;
while (i <= arr.length - zerosMin && arr[i] == 0) {
i++;
}
}
}
console.log(zeroStarts);
Note I've used filter(Boolean) because 0 is falsey; if you were searching for a run of non-zero values you would use something like filter(v => v != 0)
If you don't need to actually iterate elements, you can use a shortcut
function foo(arr, min)
{
let el = arr.join("").match(new RegExp('0{' + min + ',}'));
return [el.index, el.index + el[0].length];
}
console.log(foo([1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], 3));
For start of each chain of zeros:
function indexOfValue(arr, val) {
var indexes = [], i;
for(i = 0; i < arr.length; i++)
if (arr[i] === val)
indexes.push(i);
return indexes;
}
(see How to find index of all occurrences of element in array?)
The code you posted above appears to work for length of blocks of 0s.
While iterating the items, keep track of last non-zero index and push the index to output array when criteria matches.
const SmallestBlockOfZeros = (arr, zerosMin) => {
let index = 0;
const output = [];
for (let i = 0; i <= arr.length; i++) {
if (arr[i] !== 0 || !(i in arr)) {
i - index - 1 >= zerosMin && output.push(index + 1);
index = i;
}
}
return output;
};
const arr = [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0];
const zerosMin = 4;
console.log(SmallestBlockOfZeros(arr, zerosMin));

Check if a string exists in a 2D matrix in javascript?

I am trying to find horizontalWord string in two-dimensional array. verticalWord works fine , but I am having trouble with the horizontalWord string. Let me know if you have any ideas.
let matrix = [
[0, 'r', 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 0],
['a', 'p', 'p', 'l', 'e'],
[0, 0, 0, 0, 0]
]
function isInMatrix(matrix, word) {
for (let j = 0; j < matrix[0].length; j++) {
let verticalWord = ''
let horizontalWord = ''
for (let i = 0; i < matrix.length; i++) {
verticalWord += matrix[i][j]
}
for (let k = 0; k < matrix[0].length; k++) {
horizontalWord += matrix[j][k]
}
if ((verticalWord.includes(word)) ||
(verticalWord.split('').reverse().join('').includes(word)) ||
(horizontalWord.includes(word)) ||
(horizontalWord.split('').reverse().join('').includes(word))) return true
}
return false
}
console.log(isInMatrix(matrix, 'apple'))
Your loops are incorrect, you are only checking the first 5 rows of the matrix
for (let j = 0; j < matrix[0].length; j++) {
use (let j = 0; j < matrix.length; j++)
You could get a transpose of the matrix by using nested map
Then check if some of the inner arrays have the given word using join and includes. Check this for both the matrix and it's transpose to test horizontally and vertically
let input = [
[0, 'r', 0, 0, 0, 0, 0],
[0, 'e', 0, 0, 0, 0, 0],
[0, 'd', 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 'a', 'p', 'p', 'l', 'e', 0]
]
function isInArray(matrix, word) {
let transpose = matrix[0].map((a, i) => matrix.map(b => b[i]));
return matrix.some(a => a.join('').includes(word))
|| transpose.some(a => a.join('').includes(word))
}
console.log(isInArray(input, "apple"))
console.log(isInArray(input, "red"))
console.log(isInArray(input, "orange"))
function isInBoard(board, word) {
if (word === '') return false;
if (board.length < 1 || board[0].length < 1) return false;
const start = findStartingPoint(board, word[0]);
if (start.length < 1) return false;
for (let S of start) {
if (findPathList(board, word.slice(1), S, [])) return true;
}
return false;
}
function findPathList(B, W, S, L) {
L.push(S.join(':'));
if (!W) return true;
let r = S[0], c = S[1], rows = B.length, cols = B[0].length;
const next = [];
if (r-1 >= 0 && B[r-1][c] === W[0] && !L.includes((r-1)+':'+c)) next.push([r-1, c]);
if (r+1 < rows && B[r+1][c] === W[0] && !L.includes((r+1)+':'+c)) next.push([r+1, c]);
if (c-1 >= 0 && B[r][c-1] === W[0] && !L.includes(r+':'+(c-1))) next.push([r, c-1]);
if (c+1 < cols && B[r][c+1] === W[0] && !L.includes(r+':'+(c+1))) next.push([r, c+1]);
for (let N of next) {
const found = findPathList(B, W.slice(1), N, [...L]);
if (found) {
return true;
}
}
return false;
}
function findStartingPoint(board, s) {
const answer = [];
for (let r = 0; r < board.length; r++) {
let index = -1;
while(true) {
index = board[r].indexOf(s, index+1);
if (index >= 0) answer.push([r, index]);
else break;
}
}
return answer;
}
board = [ ['A','B','C','E'],['S','F','C','S'],['A','D','E','E'] ];
words = ["ABCCED", "SEE", "ABCB"];
// true, true, false
for (let word of words) console.log(isInBoard(board, word));
board = [ ["A","B","C","E"],["S","F","E","S"],["A","D","E","E"] ];
word = "ABCESEEEFS";
console.log(isInBoard(board, word)); // true

Copy values from one array to another, if condition satisfied

I have a matrix, that can vary in size. But for now, let's say it's a 6X6 matrix. It contains values on all the indexes, and some of these values can be 0.
Say the matrix looks like this:
var half_MW = [
[0,1,1,0,0,0],
[1,0,1,0,0,0],
[1,1,0,0,0,0],
[0,0,0,0,1,1],
[0,0,0,1,0,1],
[0,0,0,1,1,0]]
Now I want to create another array (lets call it data), and copy only the values from half_MW that don't have 0 (i.e (0,0) = 0, but also (0,3) = 0 etc.
What I'm not sure about, is how to create the array that I call data.
Here is my attempt
var half_MW = ... (values shown above)
var data = [];
for(i = 0; i < 6; ++i) {
var dataCols = [];
for(j = 0; j < 6; ++j) {
if(half_MW[i][j] != 0) {
dataCols[i] = half_MW[i];
dataCols[j] = half_MW[j];
}
}
data[i] = dataCols;
The result I get, is that the data/values are copied, but some indexes contain 0, which is what I don't want. So actually, data array, should not be a 6x6 array, it should be smaller, since those indexes from the half_MW array that contain 0 should be left out.
Your code do not work because you are missing dataCols.push(half_MW[i][j]); in the inner loop. Change that and it works:
var half_MW = [
[0,1,1,0,0,0],
[1,0,1,0,0,0],
[1,1,0,0,0,0],
[0,0,0,0,1,1],
[0,0,0,1,0,1],
[0,0,0,1,1,0]];
var data = [];
for(i = 0; i < half_MW.length; ++i) {
var dataCols = [];
for(j = 0; j < half_MW[0].length; ++j) {
if(half_MW[i][j] != 0) {
dataCols.push(half_MW[i][j]);
}
}
data[i] = dataCols;
}
console.log(data);
You can also make the loop condition more dynamic by using half_MW.length for outer loop and half_MW[0].length for inner loop.
You could map the filtering with Boolean as callback.
var half_MW = [[0, 0, 0, 0, 0, 0], [1, 0, 1, 0, 0, 0], [1, 1, 0, 0, 0, 0], [0, 0, 0, 0, 1, 1], [0, 0, 0, 1, 0, 1], [0, 0, 0, 1, 1, 0]],
result = half_MW
.map(a => a.filter(Boolean))
.filter(a => a.length);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I would use a map to loop al the arrays and return them after you filter the condition out.
I this case it looks like you want to remove all the 0s if not pliss comment so I can edit
Hope this helps :>
var half_MW = [[0,1,1,0,0,0],[1,0,1,0,0,0],[1,1,0,0,0,0],[0,0,0,0,1,1],[0,0,0,1,0,1],[0,0,0,1,1,0]];
var data = half_MW.map(m=>{
return m.filter(c=> c!=0)
})
console.log(data)

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

Categories