David Tunnell
David Tunnell

Reputation: 7542

Removing outer array object if an inner array meets a condition

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?

Upvotes: 1

Views: 1714

Answers (5)

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/

Upvotes: 1

David Tunnell
David Tunnell

Reputation: 7542

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;
    }
});

Upvotes: 0

matmo
matmo

Reputation: 1379

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);

Upvotes: 1

Pavel Kingsep
Pavel Kingsep

Reputation: 26

You should write something like this:

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

Upvotes: 0

azium
azium

Reputation: 20614

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.

Upvotes: 1

Related Questions