Sreekanth Reddy
Sreekanth Reddy

Reputation: 483

Remove given cells in 2D Array in javascript

Given an array and cell indices, remove all given cell indices.

Input:

[[0,1,2,3,4,5],
 [0,1,2,3,4,5],
 [0,1,2,3,4,5]
]

Cells:

(0,1) (1,1), (2,4), (0,2)

Expected Output:

[[0,3,4,5],
 [0,2,3,4,5],
 [0,1,2,3,5]
]

When I am trying to delete the original array is changing so that I am unable to delete the proper indices. We should not change the array till everything is removed.

  obj[key].forEach(element => {
    arr[element].splice(key, 1)
  });

Upvotes: 0

Views: 115

Answers (4)

Wiktor Maciej
Wiktor Maciej

Reputation: 259

A bit different approach.

let cellsToRemove = [
    [1, 2], //(0,1) + (0,2)
    [1], //(1,1)
    [4], //(2,4)
];
let arr = [
    [0, 1, 2, 3, 4, 5],
    [0, 1, 2, 3, 4, 5],
    [0, 1, 2, 3, 4, 5]
];


let newArr = [];
for (i = 0; i < arr.length; i++) {
    newArr.push(arr[i].filter((item) => {
        return !cellsToRemove[i].includes(item)
    }));
}
console.log(newArr);

I think Terry's solution is the best one.

Upvotes: 1

Nina Scholz
Nina Scholz

Reputation: 386560

You could sort the indices by the second index descending, because splice changes the index.

var array = [[0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5]],
    remove = [[0, 1], [1, 1], [2, 4], [0, 2]];
    
remove
    .sort((a, b) => b[1] - a[1])
    .forEach(([i, j]) => array[i].splice(j, 1));

array.map(a => console.log(...a));

Upvotes: 1

p.s.w.g
p.s.w.g

Reputation: 149010

Not the most efficient, but here's a quick and dirty solution with reduce and map:

const input = [
  [0,1,2,3,4,5],
  [0,1,2,3,4,5],
  [0,1,2,3,4,5]
];

const removals = [[0,1], [1,1], [2,4], [0,2]];
const _ = {};
const output = removals
  .reduce((a, [x, y]) => (a[x][y] = _, a), input)
  .map(r => r.filter(c => c !== _));
output.forEach(r => console.log(...r));

I'm getting around the problem of shifting indexes by simply marking the cells to remove with a placeholder (_) in one sweep, and coming back in another sweep to remove all the marked cells.

Another solution would be to sort the indexes to be removed before loop through them, and then you can just splice out items as normal.

const input = [
  [0,1,2,3,4,5],
  [0,1,2,3,4,5],
  [0,1,2,3,4,5]
];

const removals = [[0,1], [1,1], [2,4], [0,2]];
const output = removals
  .sort(([a, b], [c, d]) => d - b)
  .reduce((a, [x, y]) => (a[x].splice(y, 1), a), input);
output.forEach(r => console.log(...r));

Upvotes: 1

Terry
Terry

Reputation: 66103

Your suspicions are correct: since you are splicing the nested arrays in the matrix as you iterate through the coordinates of the cells to remove, you will end up removing the incorrect items when you return to the same row after the first time. For example:

  • Removing cell at (0,1) using Array.prototype.splice() will change the first row from [0,1,2,3,4,5] to [0,2,3,4,5]
  • When you encounter the same row again, e.g. removing another cell at (0,2), you are actually now removing 3 from the first row as the row has now since mutated

To avoid this, the only way is to replace values in the cells that you want to remove in the first pass with null. Then, run a second pass through the matrix to remove these null values:

const matrix = [
  [0,1,2,3,4,5],
  [0,1,2,3,4,5],
  [0,1,2,3,4,5]
];

const cellsToRemove = [
  [0,1],
  [1,1],
  [2,4],
  [0,2]
];

cellsToRemove.forEach(cell => {
  const x = cell[0];
  const y = cell[1];
  matrix[x][y] = null;
});

const newMatrix = matrix.map(row => {
  return row.filter(col => col !== null);
});
console.log(newMatrix);

Upvotes: 2

Related Questions