how to remove index of array inside array?

Viewed 82

I want to remove an index in an array inside a bigger arrays; for example:

 let myArray = [
  [{general : true, name: 'a' },{general : true, name: 'b' },{general : false, name: 'c' }],
  [{general : false, name: 'd' },{general : true, name: 'e' },{general : false, name: 'f'}],
  [{general : true, name: 'i' },{general : false, name: 'h' },{general : false, name: 'g' }]
]

I want to remove all objects with general == false to get this:

myFilteredArray = [
      [{general : true, name: 'a' },{general : true, name: 'b' }],
      [{general : true, name: 'e' }],
      [{general : true, name: 'i' }]
    ]

I did this but it doesn't work:

let l = myArray.length;
      for (let i = 0; i < l; i++) {
        for (let j = 0; j < myArray[i].length; j++) {
          if(!myArray[i][j].general){
            myArray[i].splice(j,1)
          }
        }
      }

thanks in advance.

2 Answers

The problem is when you have two objects with general: false next to each other. You're looking at index j, and possibly removing that entry, and then moving on to the next entry after it — but when you remove an entry, the one after it moves up to index j and never gets checked.

Three options:

  1. When you remove the entry, decrement j so you check the entry that moved on the next pass.

  2. Loop backward from the end.

  3. Use filter to create new arrays, rather than modifying arrays in place, perhaps combined with map on the outer array:

#2 is more popular than #1:

let l = myArray.length;
for (let i = 0; i < l; i++) {
    for (let j = myArray[i].length - 1; j >= 0; --j) {
        if (!myArray[i][j].general) {
            myArray[i].splice(j,1)
        }
    }
}

Live example:

let myArray = [
    [{general : true, name: 'a' },{general : true, name: 'b' },{general : false, name: 'c' }],
    [{general : false, name: 'd' },{general : true, name: 'e' },{general : false, name: 'f'}],
    [{general : true, name: 'i' },{general : false, name: 'h' },{general : false, name: 'g' }]
];

let l = myArray.length;
for (let i = 0; i < l; i++) {
    for (let j = myArray[i].length - 1; j >= 0; --j) {
        if (!myArray[i][j].general) {
            myArray[i].splice(j,1)
        }
    }
}
console.log(myArray);

Here's #3:

myArray = myArray.map(subarray => subarray.filter(({general}) => general));

Live example:

let myArray = [
    [{general : true, name: 'a' },{general : true, name: 'b' },{general : false, name: 'c' }],
    [{general : false, name: 'd' },{general : true, name: 'e' },{general : false, name: 'f'}],
    [{general : true, name: 'i' },{general : false, name: 'h' },{general : false, name: 'g' }]
];

myArray = myArray.map(subarray => subarray.filter(({general}) => general));
console.log(myArray);

It turns out reduce is a solid solution

let myArray = [
  [{general : true, name: 'a' },{general : true, name: 'b' },{general : false, name: 'c' }],
  [{general : false, name: 'd' },{general : true, name: 'e' },{general : false, name: 'f'}],
  [{general : false, name: 'x' },{general : false, name: 'y' },{general : false, name: 'z' }], // all false
  [{general : true, name: 'i' },{general : false, name: 'h' },{general : false, name: 'g' }]
]

const filtered = myArray.reduce((acc, arr) => {
  let flt = arr.filter(item => item.general)
  if (flt.length) acc.push(flt) 
  return acc; 
},[]);

console.log(filtered)

I first thought this, but it is not matching OP's output.

let myArray = [
  [{general : true, name: 'a' },{general : true, name: 'b' },{general : false, name: 'c' }],
  [{general : false, name: 'd' },{general : true, name: 'e' },{general : false, name: 'f'}],
  [{general : true, name: 'i' },{general : false, name: 'h' },{general : false, name: 'g' }]
]

const filtered = myArray.map(arr => arr.filter(item => item.general)).flat()

console.log(filtered)

Related