2

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.

mohammad
  • 505
  • 4
  • 17

2 Answers2

2

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);
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
2

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)
mplungjan
  • 169,008
  • 28
  • 173
  • 236
  • @kopischke Not sure I understand – mplungjan Nov 17 '20 at 12:45
  • But if I do that, then it does not look like OP wants - then it looks like my second example – mplungjan Nov 17 '20 at 12:53
  • Ah, sorry, totally misread that, my bad. Forget my remarks. – kopischke Nov 17 '20 at 12:58
  • The second code example has thrown me. Your first one works as intended, correct? Upvoted. – kopischke Nov 17 '20 at 13:00
  • `reduce` when you're not doing functional programming with predefined, reusable reducers is overcomplicated at the best of times, but particularly so when the value being carried around (the new array) never changes. Just use a loop. (Or, of course, the `map`/`filter` we both like. :-) ) – T.J. Crowder Nov 17 '20 at 13:13
  • Hm, sort of get that - I like the name reduce because that is what OP wants to do. Reduce to only arrays with true – mplungjan Nov 17 '20 at 13:18