Gervis Dillon
Gervis Dillon

Reputation: 13

Javascript Filtering Array of Objects using Filter Question

I have 2 arrays of objects. Seen below

var subs = new Array();
var list_items = new Array();

subs = [
  { "value": 3, "text": "Guyana" }, 
  { "value": 4, "text": "St Lucia" }, 
  { "value": 5, "text": "Suriname" }, 
  { "value": 6, "text": "Barbados" }, 
  { "value": 7, "text": "3rd Party" }, 
  { "value": 8, "text": "JDL" }
];
    
list_items = [
  { "Id": 168, "Month": "May", "Resent": false, "Stage": "2", "StageRecipNum": 3, "Title": "Demand_Forecast_2020_Month_May", "parentID": "51" },
  { "Id": 169, "Month": "May", "Resent": false, "Stage": "2", "StageRecipNum": 4, "Title": "Demand_Forecast_2020_Month_May", "parentID": "51" },
  { "Id": 170, "Month": "May", "Resent": false, "Stage": "2", "StageRecipNum": 6, "Title": "Demand_Forecast_2020_Month_May", "parentID": "51" },
  { "Id": 171, "Month": "May", "Resent": false, "Stage": "2", "StageRecipNum": 5, "Title": "Demand_Forecast_2020_Month_May", "parentID": "51" }
];

What I'm trying to do is filter the "Subs" array, where any objects in the "list_items" array with the attribute ("StageRecipNum" matching the Subs "value" and "Resent" = false) should be removed from "Subs".

Here is the code I have to try to do this.

for (var i = 0; i < subs.length; i++) {
  for (var j = 0; j < list_items.length; j++) {
    if (parseInt(subs[i].value) == parseInt(list_items[j].StageRecipNum) && 
        list_items[j].Resent == false) {
      var hold = parseInt(list_items[j].StageRecipNum);
      subs = subs.filter(el => el.value !== hold);
      console.log(subs);
    }
  }
}

Afterward I am taking the remaining "Subs" array items and putting it in a dropdownlist to display on a form. All that works, the issue I am having is that one of the items in the list_items array keeps returning in the dropdownlist when it's not supposed to be there.

In the java console of visual studio code using Quokka, I get the below

Code Test Screenshot

As you can see, number 6 which is Barbados is not supposed to be there. I can't figure out why it's there and all the rest that not supposed to be in the array are not there. Only the 3rd Party and JDL supposed to be on the list.

I need help. What did I do wrong?

Upvotes: 1

Views: 74

Answers (3)

Joost Molenkamp
Joost Molenkamp

Reputation: 168

The problem arises because you are altering the array which you are looping over. The loop ends prematurely, because the length of the array is no longer the original length after removing items, resulting in not evaluating the remaining items.

To keep using the same code, keep updating a copy of the array while keeping the subs variable in its original state.

Below a less verbose way of achieving the same result. Filter the list_items for values where Resent is false and select its StageRecipNum. Next, filter the subs for values where the value is not contained by the list items:

var subs = [
  { "value": 3, "text": "Guyana" }, 
  { "value": 4, "text": "St Lucia" }, 
  { "value": 5, "text": "Suriname" }, 
  { "value": 6, "text": "Barbados" }, 
  { "value": 7, "text": "3rd Party" }, 
  { "value": 8, "text": "JDL" }
];
    
var list_items = [
  { "Id": 168, "Month": "May", "Resent": false, "Stage": "2", "StageRecipNum": 3, "Title": "Demand_Forecast_2020_Month_May", "parentID": "51" },
  { "Id": 169, "Month": "May", "Resent": false, "Stage": "2", "StageRecipNum": 4, "Title": "Demand_Forecast_2020_Month_May", "parentID": "51" },
  { "Id": 170, "Month": "May", "Resent": false, "Stage": "2", "StageRecipNum": 6, "Title": "Demand_Forecast_2020_Month_May", "parentID": "51" },
  { "Id": 171, "Month": "May", "Resent": false, "Stage": "2", "StageRecipNum": 5, "Title": "Demand_Forecast_2020_Month_May", "parentID": "51" }
];


var list_item_nums = list_items.filter(x => !x.Resent).map(x => x.StageRecipNum);
var filtered_subs = subs.filter(x => !list_item_nums.includes(x.value));

console.log(filtered_subs);

Upvotes: 1

Nina Scholz
Nina Scholz

Reputation: 386670

You could take a Set and filter the array.

const
    subs = [{ value: 3, text: "Guyana" }, { value: 4, text: "St Lucia" }, { value: 5, text: "Suriname" }, { value: 6, text: "Barbados" }, { value: 7, text: "3rd Party" }, { value: 8, text: "JDL" }],        
    list_items = [{ Id: 168, Month: "May", Resent: false, Stage: "2", StageRecipNum: 3, Title: "Demand_Forecast_2020_Month_May", parentID: "51" }, { Id: 169, Month: "May", Resent: false, Stage: "2", StageRecipNum: 4, Title: "Demand_Forecast_2020_Month_May", parentID: "51" }, { Id: 170, Month: "May", Resent: false, Stage: "2", StageRecipNum: 6, Title: "Demand_Forecast_2020_Month_May", parentID: "51" }, { Id: 171, Month: "May", Resent: false, Stage: "2", StageRecipNum: 5, Title: "Demand_Forecast_2020_Month_May", parentID: "51" }],
    values = new Set(list_items.map(({ StageRecipNum }) => StageRecipNum)),
    result = subs.filter(({ value }) => !values.has(value));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 0

Rajneesh
Rajneesh

Reputation: 5308

You can apply filter with some on the second array by matching StageRecipNum with value and resent property to be false. and once found take negate of some. Something like this:

const subs = [ { "value": 3, "text": "Guyana" }, { "value": 4, "text": "St Lucia" }, { "value": 5, "text": "Suriname" }, { "value": 6, "text": "Barbados" }, { "value": 7, "text": "3rd Party" }, { "value": 8, "text": "JDL" } ];
    
const list_items = [ { "Id": 168, "Month": "May", "Resent": false, "Stage": "2", "StageRecipNum": 3, "Title": "Demand_Forecast_2020_Month_May", "parentID": "51" }, { "Id": 169, "Month": "May", "Resent": false, "Stage": "2", "StageRecipNum": 4, "Title": "Demand_Forecast_2020_Month_May", "parentID": "51" }, { "Id": 170, "Month": "May", "Resent": false, "Stage": "2", "StageRecipNum": 6, "Title": "Demand_Forecast_2020_Month_May", "parentID": "51" }, { "Id": 171, "Month": "May", "Resent": false, "Stage": "2", "StageRecipNum": 5, "Title": "Demand_Forecast_2020_Month_May", "parentID": "51" } ];
    
const result = subs.filter(a=>!list_items.some(b=>b.StageRecipNum===a.value && b.Resent===false));

console.log(result);

Upvotes: 1

Related Questions