1

I am dealing with a fairly complex object. It contains 2 arrays, which contain 3 arrays each of objects:

enter image description here

I'm trying to delete one of the history: Array[2] if one of the objects in it has username: null.

var resultsArray = result.history;
var arrayCounter = 0;

resultsArray.forEach(function(item) {
    item.forEach(function(innerItem) {
        if (innerItem.username == null) {
            resultsArray.splice(arrayCounter,1);
        };
    });
    arrayCounter++;
});

Looking through answers it's recommended to do something like:

resultsArray.splice(arrayCounter,1);

This isn't working in this situation because more than one of the objects could have username == null and in that case it will delete multiple history objects, not just the one that I want.

How do I remove only the one specific history array index if username == null?

Anmol Saraf
  • 15,075
  • 10
  • 50
  • 60
David Tunnell
  • 7,252
  • 20
  • 66
  • 124
  • What's stopping you from just iterating through resultsArray and it's child arrays with regular for(;;) syntax, and then breaking out of the loops when the first match has been encountered and dealt with? – matmo Dec 22 '15 at 22:02
  • Breaking in the inner array after the 1st match would stop the whole thing and not evaluate the 2nd (in this case) history: Array[2]. Right? – David Tunnell Dec 22 '15 at 22:04
  • 1
    All possible options described in this question: http://stackoverflow.com/questions/6260756/how-to-stop-javascript-foreach – Dmitry Dec 22 '15 at 22:15

5 Answers5

1

splice is evil. I think using immutable array methods like filter might be easier to reason about:

x.history =
  x.history.filter(function (h) {
    return !h.some(function (item) {
      return item.username === null
    })
  })

Go through all the histories, and do not include them in the filter if they have a username that is null.

azium
  • 20,056
  • 7
  • 57
  • 79
1

My understanding was that you only want to delete the first outer array that has an inner array that has an object with a null username. Heres one solution closest to your current form:

var resultsArray = result.history;
var arrayCounter = 0;
var foundFirstMatch = false;

resultsArray.forEach(function(item) {
    if (!foundFirstMatch) {
        item.forEach(function(innerItem) {
            if (innerItem.username == null && !foundFirstMatch) {
                foundFirstMatch = true;
            };
        });
        arrayCounter++;        
     }
});


if (foundFirstMatch > 0)
    resultsArray.splice(arrayCounter, 1);

Other syntax:

var resultsArray = result.history;
var outerNdx;
var innerNdx;
var foundMatch = false;

for (outerNdx = 0; !foundMatch && outerNdx < resultsArray.length; outerNdx++) {
   for (innerNdx = 0; !foundMatch && innerNdx < resultsArray[outerNdx].length; innerNdx++) {
      if (resultsArray[outerNdx][innerNdx].username == null) {
         foundMatch = true;
      }
    }
 }

 if (foundMatch)
    resultsArray.splice(outerNdx, 1);
matmo
  • 1,339
  • 12
  • 17
1

Update - here's how I'd do it now, without lodash:

thing.history.forEach((arr, i) => {
  thing.history[i] = arr.filter( (x) => x.username !== null );
});

Previous answer:

I'd use lodash like this:

_.each(thing.history, function(array, k){
  thing.history[k] = _.filter(array, function(v){
    return v.username !== null;
  })
});

Here's a jsfiddle:

https://jsfiddle.net/mckinleymedia/n4sjjkwn/2/

0

You should write something like this:

var resultsArray = result.history.filter(function(item){
    return !item.some(function(inner){ return inner.username==null; });
});
0

The foreach loop cant break in this way but a regular for loop can. This is working:

result.history.forEach(function(item) {
    loop2:
    for (var i = 0; i < item.length; i++) {
        var innerItem = item[i];
        console.log(innerItem);
        break loop2;
    }
});
Cody
  • 484
  • 6
  • 20
David Tunnell
  • 7,252
  • 20
  • 66
  • 124