Javascript 2d arrays remove the same elemets like dropping style - javascript

Forexample, I have an array like this:
const arr = [
[1, 2, 8],
[8, 5, 6],
[7, 8, 9]
];
And I want to remove the number 8 from bottom to top like dropping. Forexample:
const arr = [
[null, null, null],
[1, 2, 6],
[7, 5, 9]
];
I will replace the nulls later.

Loop through your array from the bottom to the top, then inside loop over each row. If the current item you find is an 8 - then drop all previous items in the same row down by one position, and set null on that position for the first row.
const arr = [
[1, 2, 8],
[8, 5, 6],
[7, 8, 9]
];
for (let i = arr.length - 1; i >= 0; --i) {
for (let j = 0, l = arr.length; j < l; ++j) {
if (arr[i][j] == 8) {
for (let k = i; k > 0; --k) {
arr[k][j] = arr[k - 1][j];
}
arr[0][j] = null;
}
}
}
console.log(JSON.stringify(arr));

Related

How to offset matrix values from up to down by row in Javasript?

I have a matrix and a flip_value that goes for the first element, I want to offset or push down the numbers of a selected column.
For example
let matrix = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16],
];
I want to change the matrix-like that:
So in the second (1st row in the program) is pushed down by 1 and the first element changed.
flip_value = 999
let matrix = [1, 999, 3, 4],
[5, 2, 7, 8],
[9, 6, 11, 12],
[13, 10, 15, 16],
The new flip value is 14.
Could you also give me a hint on how to do this from down to up?
flip_value = 999
Like that:
let matrix = [
[1, 6, 3, 4],
[5, 10, 7, 8],
[9, 14, 11, 12],
[13, 999, 15, 16],
];
//In this method the second-row values are pushed down to up by 1 and the last value in second row the last element flipped.
The new flip_value = 2 here
The whole code which is not working
let matrix = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16],
];
let Yindex = 1;
let flip_value = 999;
let size = 4;
let flip_tmp = matrix[size - 1][Yindex];
console.log("fontos");
for (let i = 1; i < size; i++) {
// matrix[i][Yindex] = matrix[i-1][Yindex];
let tmp = matrix[i][Yindex];
matrix[i][Yindex] = matrix[i - 1][Yindex];
matrix[i - 1][Yindex] = tmp;
console.log(matrix[i][Yindex] + "=" + matrix[i - 1][Yindex]);
}
matrix[0][Yindex] = flip_value;
flip_value = flip_tmp;
for (let i = 0; i < size; i++) {
console.log("\n");
for (let j = 0; j < size; j++) {
console.log(matrix[i][j] + " ");
}
}
for (let i = 0; i < size; i++) {
console.log("\n");
for (let j = 0; j < size; j++) {
if (j == 1) {
console.log(i + "" + j + " " + matrix[i][j] + " ");
}
}
}
From down to up or from up to down are pretty similar, speaking of the logic.
There are just three things that changes between them:
Change\Type of push
Up-down
Down-up
flip_tmp (1)
matrix[0][Yindex]
matrix[size - 1][Yindex]
for-loop (2)
for(i = 1; i < size; i++)
for(i = size - 1; i > 0; i--)
matrix's flip value (3)
matrix[size - 1][Yindex]
matrix[0][Yindex]
With this said, you can adapt your code to handle either case by passing it as a string, for example.
let pushDirection = "up-down"; // or down-up if not specified
let Yindex = 1;
let flip_value = 999;
let flip_tmp;
function swap(matrix, i, j){
let tmp = matrix[i][j];
matrix[i][j] = matrix[i - 1][j];
matrix[i - 1][j] = tmp;
}
let matrix = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16],
];
let size = matrix.length
if(pushDirection === "up-down"){
flip_tmp = matrix[0][Yindex]; // 1
for(let i = 1; i < size; i++) { // 2
swap(matrix, i, Yindex);
}
matrix[size - 1][Yindex] = flip_value; // 3
}
else { // down-up
flip_tmp = matrix[size - 1][Yindex]; // 1
for(let i = size-1; i > 0; i--) { // 2
swap(matrix, i, Yindex);
}
matrix[0][Yindex] = flip_value; // 3
}
flip_value = flip_tmp;
console.log("Push direction:", pushDirection, "\n", JSON.stringify(matrix).replaceAll('],','],\n'))
console.log("New flip value: ", flip_value)
Abstraction is a useful idea here. First, the matrix can abstracted as object with accessors that hide the internal representation. The accessors the OP needs are get/set column.
An array that rotates and keeps state is another tool that solves this problem (and maybe others).
class Matrix {
constructor(arrayOfArrays) {
this.array = arrayOfArrays
}
getColumn(j) {
// out of bounds check for the reader
return this.array.map(row => row[j])
}
setColumn = (j, colValues) => {
// array length and out of bounds check for the reader
this.array.forEach((row, i) => row[j] = colValues[i])
}
// just for illustration.. more like this left to the reader
getRow(i) { return this.array[i] }
print() {
this.array.forEach(row => console.log(JSON.stringify(row)))
}
}
// array that rotates and keeps state about the last value popped
class RotatingArray {
constructor(array) {
this.array = array
this.rotateValue = null
}
rotateForward(value) {
value = value || this.rotateValue
this.rotateValue = this.array[this.array.length-1]
this.array = [value, ...this.array.slice(0, -1)];
return this.array
}
rotateReverse(value) {
value = value || this.rotateValue
this.rotateValue = this.array[0]
this.array = [...this.array.slice(1), value];
return this.array
}
}
// those are the tools needed to solve the problem
// testing, rotate the 1st col forward with 999, do it twice
let data = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16],
];
let matrix = new Matrix(data)
let firstCol = matrix.getColumn(1);
let rArr = new RotatingArray(firstCol);
firstCol = rArr.rotateForward(999)
matrix.setColumn(1, firstCol);
matrix.print();
firstCol = rArr.rotateForward()
matrix.setColumn(1, firstCol);
console.log('after a second rotation')
matrix.print();

"Maximum call stack size exceeded" Correct method but not efficient enough? Codewars Kata “Stop the Zombie Apocalypse!”

I am attempting to solve this kata- https://www.codewars.com/kata/stop-the-zombie-apocalypse/train/javascript
I think I have a method that should work, but is too slow/inefficient and I am getting the error "Maximum call stack size exceeded". I would greatly appreciate all responses as dumbed down as possible as I am new to this. If you could point me in the direction of a different way of doing this, or somehow tweaking my method preferably.
function findZombies(matrix) {
var n = matrix.length;
var value = 0;
//create 2 new arrays with 2 extras row and columns
var arr1 = [...Array(n + 2)].map(e => Array(n + 2).fill(value));
var arr2 = [...Array(n + 2)].map(e => Array(n + 2).fill(value));
//change arr1 so that all infected numbers = 2, everything else = 0
//leaving first and last rows and columns blank
for (var i = 0; i < n; i++) {
for (var j = 0; j < n; j++) {
if (matrix[i][j] == matrix[0][0]) {
arr1[i + 1][j + 1] = 2;
}
}
}
//if element in arr1 has a link back to arr[1][1] call the function recursively until there is no link
//Then return arr2 with changed elements.
function recur(arr1, arr2, i, j) {
if (arr1[i][j] == 2 && arr1[i][j] == arr1[i + 1][j]) {
arr2[i][j] = 1;
recur(arr1, arr2, (i + 1), j)
}
if (arr1[i][j] == 2 && arr1[i][j] == arr1[i][j + 1]) {
arr2[i][j] = 1;
recur(arr1, arr2, i, (j + 1))
}
if (arr1[i][j] == 2 && arr1[i][j] == arr1[i - 1][j]) {
arr2[i][j] = 1;
recur(arr1, arr2, (i - 1), j)
}
if (arr1[i][j] == 2 && arr1[i][j] == arr1[i][j - 1]) {
arr2[i][j] = 1;
recur(arr1, arr2, i, (j - 1))
} else {
return arr2;
console.log(arr2)
}
}
recur(arr1, arr2, 1, 1);
//clean up array by removing empty outside rows and columns
arr2.shift();
arr2.pop();
for (var i = 0; i < n; i++) {
arr2[i].shift();
arr2[i].pop()
}
console.log(arr2);
}
var matrix = [
[9, 1, 2],
[9, 9, 9],
[7, 4, 9],
[7, 9, 7]
];
var matrix2 = [
[8, 2, 3, 8, 8],
[8, 0, 8, 8, 8],
[1, 2, 8, 4, 8],
[8, 2, 3, 8, 8],
[8, 8, 8, 0, 5]
];
findZombies(matrix)
You could store all valid points (zombies) in a nested hash table with the all zombies and their adjacent zombies.
At the end start with the known zombie at [0][0] and take the array of the ahsh table to visit all connected field. For preventing visiting already visited items, replace the array with undefined.
function findZombies(matrix) {
function go([i, j]) {
if (!tree[i] || !tree[i][j]) return;
result[i][j] = 1;
var temp = tree[i][j];
tree[i][j] = undefined;
temp.forEach(go);
}
var i, j,
result = [],
zombie = matrix[0][0],
tree = {};
for (i = 0; i < matrix.length; i++) {
result.push([]);
for (j = 0; j < matrix[i].length; j++) {
result[i].push(0);
if (matrix[i][j] !== zombie) continue;
if (!tree[i]) tree[i] = {};
tree[i][j] = [[i, j - 1], [i, j + 1], [i - 1, j], [i + 1, j]].filter(([x, y]) => matrix[x] && matrix[x][y] === zombie);
}
}
go([0, 0]);
return result;
}
var matrix = [[9, 1, 2, 3, 4, 1, 2, 9], [9, 9, 9, 2, 1, 5, 9, 9], [9, 2, 9, 3, 7, 9, 1, 9], [6, 9, 9, 9, 0, 9, 2, 9], [5, 4, 3, 9, 9, 9, 4, 9], [9, 3, 9, 5, 8, 9, 9, 9], [9, 9, 9, 9, 9, 9, 7, 9], [9, 9, 1, 2, 3, 9, 8, 9]],
result = findZombies(matrix);
result.forEach(a => console.log(...a));
.as-console-wrapper { max-height: 100% !important; top: 0; }

how to check if 2 rows are symmetrical?

i have 2 rows that i need to check in java script if they are symmetrical
row 1 [2, 7, 9, 9, 7, 2] row 2 [5 7 3 3 7 5] how would you do it ?
var r = [[5, 7, 3, 3, 7, 5], [2, 7, 9, 9, 7, 2]];
function isSymmetric(r) {
// convert to object
var rel = {}
for (var i = 0; i < r.length; i++) {
if (!(r[i][0] in rel)) rel[r[i][0]] = {};
rel[r[i][0]][r[i][1]] = true;
}
// Test to see if opposite relation is in object
for (var a in rel) {
for (var b in rel[a]) {
if (!rel[b] || !rel[b][a]) return false;
}
}
return true;
}
console.log(isSymmetric(r));
You could do something like this:
let isSymmetric = arr => {
for(var i=0; i < arr.length; i++) {
if(arr[i] !== arr[arr.length - (i+1)])
return false
}
return true
}
console.log(isSymmetric([5, 7, 3, 3, 7, 5]))
console.log(isSymmetric([1, 7, 9, 9, 7, 2]))
The idea is to loop through the array and for each index compare with its "sibling" from the right side. If one is not the same them return false.
You can start from 0th index and compare the value with its symmetric pair (length - 1 - i), and if they are not same then return false. You should stop at the middle length / 2:
let values = [
[5, 7, 3, 3, 7, 5],
[2, 7, 9, 1, 9, 7, 2],
[5, 7, 3, 3, 7, 1]
];
function isSymmetric(arr) {
for (let i = 0; i < arr.length / 2; i++) {
if (arr[i] !== arr[arr.length - 1 - i]) {
return false;
}
}
return true;
}
values.forEach(v =>
console.log(isSymmetric(v))
);
Use lodash.
var row = [2, 7, 9, 9, 7, 2];
var halves = _.chunk(row, _.ceil(row.length / 2));
var result = _.isEqual(halves[0], _.reverse(halves[1]));

loop through 2D array horizontally - javascript

how do loop through this 3x3 grid of arrays horizontally and print out 1, 4, 7, 2, 5, 8, 3, 6, 9?
edit: is there a more efficient way of doing this other than to use a two loops that also works if the length of the arrays are not equal to the other ones?
let grid = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
You can use nested for Loops:
let grid = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
];
for(let i = 0; i < grid[0].length; i++){
for(let j = 0; j < grid.length; j++)
console.log(grid[j][i]);
}
You have a lot of answers that work if the arrays are all the same length. Here's a way to handle potentially different length arrays. It basically runs until it can't find any more data:
let grid = [
[1, 2, 3, 4, 5],
[4, 5, 6, 7],
[7, 8, 9, 10, 11, 12]
];
let current = grid, i = 0
while(current.length){
current = grid.filter(arr => i < arr.length)
current.forEach(arr => console.log(arr[i]))
i++
}
for(var i = 0; i < grid.length; i++) {
var arr = grid[i];
for(var j = 0; j < arr.length; j++) {
console.log("array[" + i + "][" + j + "] = " + arr[j]);
}
}
you just have to find the sizes of the inner array and outer array
for(let i=0;i<countYourArraySize;i++)
{
for(let j=0;j<countYourInnerArayLength;j++)
{
console.log(grid[j][i])
}
}
let grid = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
let gridLength = grid[0].length;
let gridHeight = grid.length;
for(let l1=0; l1<gridLength;l1++) {
for(let l2=0; l2<gridHeight;l2++) {
console.log(grid[l2][l1]);
}
}
Assuming grid is rectangular(and grids usually are ;)), you can loop through it, columns first, rows second like in this snippet.
There was a question if we can do it without 2 loops, we can and I think its actually better and cleaner solution:
let grid = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
let gridLength = 3;
for(let l1=0; l1<gridLength*gridLength;l1++) {
console.log(grid[l1%gridLength][Math.floor(l1/gridLength)]);
}
You can do it with just one (explicit) loop if you use map:
let grid = [
[1,2,3],
[4,5,6],
[7,8,9]
];
let result = [];
for (let i=0; i < grid.length; i++) {
result = result.concat(grid.map((row) => row[i])));
}
console.log(result);
You can do this in a single loop. But the length must same for this
let grid = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
for (var i = 0; i < grid.length*grid.length; i++) {
var row = Math.floor(i / grid.length);
var col = i % grid.length;
console.log(grid[col][row]);
}
You need to make use of a nested for loop:
So please have a look at my solution:
let grid = [
[1,2,3],
[4,5,6],
[7,8,9]
];
for (let x = 0; x < grid[0].length; x++) {
for (let y = 0; y < grid.length; y++) {
console.log(grid[y][x]);
}
}
This grid prints out the expected solution: 1, 4, 7, 2, 5, 8, 3, 6, 9?
Some explanation:
In this case we are using two different for-loops.
the outer one for the X for (let x = 0; x < 3; x++) {}
the inner one for the Y for (let y = 0; y < 3; x++) {}
Note: This will just work if the grid is rectangular because using grid[0].length will otherwise produce an error.
Edit: If you just want to use a single loop try something like this:
let grid = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
];
for (let i = 0 ; i < grid.length * grid[0].length ; i++)
console.log(grid[i % grid.length][parseInt(i / grid.length)]);

Codewars javascript task - help to understand

I am taking an excercise on codewars:
Given a list of integers and a single sum value, return the first two
values (parse from the left please) in order of appearance that add up
to form the sum.
Example:
sum_pairs([10, 5, 2, 3, 7, 5], 10)
# ^-----------^ 5 + 5 = 10, indices: 1, 5
# ^--^ 3 + 7 = 10, indices: 3, 4 *
# * entire pair is earlier, and therefore is the correct answer
== [3, 7]
What do you think entire pair is earlier means? IMO if the sum of it's indexes is smallest. Now based on this assumption I made my solution and one test fails:
var sum_pairs=function(ints, s){
let i = 0;
let pair = [0, 0];
let ind = [100, 100]
let found = false;
function loop(i) {
if (i > ints.length) return pair;
ints.slice(i).forEach((curr, idx) => {
ints.slice(i+1).some((num, i) => {
let sum = curr + num;
let prevIndicies = ind[0] + ind[1];
if(sum === s && prevIndicies > idx + i) {
ind = [idx, i];
pair = [curr, num];
found = true;
return true;
}
})
})
i += 1;
loop(i)
}
loop(0)
if (found) {
return pair
}
return undefined;
}
console.log(sum_pairs([1,4,8,7,3,15], 8))
Test returns error that [1, 7] is expected.
I'm pretty sure what it means is they want the second element to be as leftward in the list as possible. For example, for
l5= [10, 5, 2, 3, 7, 5];
when trying to find a sum of 10, the desired output is
[3, 7]
[10, 5, 2, 3, 7, 5];
^ ^
instead of
[5, 5]
[10, 5, 2, 3, 7, 5];
^ ^
because the last element in [3, 7], the 7, came before the second 5.
This code seems to pass all test cases - iterate in a triangular fashion, starting at indicies [0, 1], [0, 2], [1, 2], [0, 3], [1, 3], [2, 3], ...:
const sum_pairs = function(ints, s){
const { length } = ints;
for (let i = 1; i < length; i++) {
for (let j = 0; j < i; j++) {
if (ints[i] + ints[j] === s) return [ints[j], ints[i]];
}
}
}
const sum_pairs=function(ints, s){
const { length } = ints;
for (let i = 1; i < length; i++) {
for (let j = 0; j < i; j++) {
if (ints[i] + ints[j] === s) return [ints[j], ints[i]];
}
}
}
l1= [1, 4, 8, 7, 3, 15];
l2= [1, -2, 3, 0, -6, 1];
l3= [20, -13, 40];
l4= [1, 2, 3, 4, 1, 0];
l5= [10, 5, 2, 3, 7, 5];
l6= [4, -2, 3, 3, 4];
l7= [0, 2, 0];
l8= [5, 9, 13, -3];
console.log(sum_pairs(l1, 8))
console.log(sum_pairs(l2, -6))
console.log(sum_pairs(l3, -7))
console.log(sum_pairs(l4, 2))
console.log(sum_pairs(l5, 10))
console.log(sum_pairs(l6, 8))
console.log(sum_pairs(l7, 0))
console.log(sum_pairs(l8, 10))
It means that you go from left to right and take the first matching pair, and since 7 is the first element that creats a pair (going from the left) 3 and 7 is the first pair.
I would solve it a bit easier:
function sum_pairs(arr, target) {
let old = [];
let result = [];
arr.some((el) => {
let found = old.find((oldEl) => oldEl + el === target);
if (found) return result = [found, el];
old.push(el);
})
return result;
}
sum_pairs([10, 5, 2, 3, 7, 5], 10);
Edit: an explaination. I loop over all elements in the array searching for a match i all the elements I have passed. If I find a match I remember it and break out of the loop by returning a "truthy" value. (That is just how .some() works.) Finally if I have not found a match I add the element to my list of old elements and go on to the next.
function sum_pair(arr,sum){
let result = [];
arr.forEach((i, j)=>{
if(i+arr[j+1]===sum){
console.log(i,arr[j+1], i+arr[j+1])
}
})
}
sum_pair([0, 3, 7, 0, 5, 5],10)

Categories