Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set condition when using filter?

I'm trying to return all the items which broke a relationship in the following array:

[
   { id: "1", option: { bound_id: "2" }},
   { id: "2", option: { bound_id: "12" }},
   { id: "12", option: { bound_id: "2" }}
]

As you can see each item is linked each other using the property bound_id, if a property broke a relation like:

[
   { id: "1", option: { bound_id: null }},
   { id: "2", option: { bound_id: "12" }},
   { id: "12", option: { bound_id: "2" }}
]

the following result is returned:

[
   { id: "2", option: { bound_id: "12" }}
   { id: "12", option: { bound_id: "2" }}
]

I'm using the following code:

const input = [
   { id: "1", option: { bound_id: null }},
   { id: "2", option: { bound_id: "12" }},
   { id: "12", option: { bound_id: "2" }}
];

const output = input.filter(a => a.option.bound_id);

console.log(output);

I want to include is to insert only the relationship of the items which are next, an example is better:

[
   { id: "1", option: { bound_id: "2" }},
   { id: "2", option: { bound_id: "3" }},
   { id: "12", option: { bound_id: "2" }}
]

as you can see the item with id 2 broke the relation with id 12 and point to an item with id 3 that doesn't exist in the collection, in this scenario the output should be:

[
   { id: "1", option: { bound_id: "2" }},
   { id: "2", option: { bound_id: "3" }}
]

how can I do this using filter?

like image 870
teres Avatar asked Jan 20 '19 20:01

teres


2 Answers

While using .filter, you might add to a Set of the ids, and .filter by whether the bound_id being iterated over is included in the Set yet (if not, add it to the set; if so, have the item fail the .filter test). Also keep the item if the index is 0, since you always want to keep the first record:

const input = [
   { id: "1", option: { bound_id: "2" }},
   { id: "2", option: { bound_id: "3" }},
   { id: "12", option: { bound_id: "2" }}
];
const alreadyHave = new Set();
const filtered = input.filter(({ option }, index) => {
  const { bound_id } = option;
  if (!alreadyHave.has(bound_id) || index === 0) {
    alreadyHave.add(bound_id);
    return true;
  }
});
console.log(filtered);

If, per comment, you actually want to always remove the first item, then change the condition to && index !== 0:

const input = [
   { id: "1", option: { bound_id: "2" }},
   { id: "2", option: { bound_id: "3" }},
   { id: "12", option: { bound_id: "2" }}
];
const alreadyHave = new Set();
const filtered = input.filter(({ option }, index) => {
  const { bound_id } = option;
  if (!alreadyHave.has(bound_id) && index !== 0) {
    alreadyHave.add(bound_id);
    return true;
  }
});
console.log(filtered);

Or, per comment, if the logic for the first item should be the same, remove the index condition entirely:

const input = [
   { id: "1", option: { bound_id: "2" }},
   { id: "2", option: { bound_id: "3" }},
   { id: "12", option: { bound_id: "2" }}
];
const alreadyHave = new Set();
const filtered = input.filter(({ option }, index) => {
  const { bound_id } = option;
  if (!alreadyHave.has(bound_id)) {
    alreadyHave.add(bound_id);
    return true;
  }
});
console.log(filtered);
like image 123
CertainPerformance Avatar answered Oct 23 '22 16:10

CertainPerformance


My proposal is based on cross checking:

const input1 = [
    { id: "1", option: { bound_id: null }}
];
const input2 = [
    { id: "1", option: { bound_id: "2" }},
    { id: "2", option: { bound_id: "3" }},
    { id: "12", option: { bound_id: "2" }}
];
const input3 = [
    { id: "1", option: { bound_id: null }},
    { id: "2", option: { bound_id: "12" }},
    { id: "12", option: { bound_id: "2" }}
];
const input4 = [
   { id: "1", option: { bound_id: "2" }},
   { id: "2", option: { bound_id: "12" }},
   { id: "12", option: { bound_id: "2" }}
];

var f = (arr) =>  {
    if (arr.length == 1)
        return arr;
    return arr.filter(function (e, i, a) {
        return (!!a[i+1] && e.option.bound_id == a[i+1].id) ||
                (!!a[i-1] && e.id == a[i-1].option.bound_id);
    })
};

console.log(f(input1));
console.log(f(input2));
console.log(f(input3));
console.log(f(input4));
like image 1
gaetanoM Avatar answered Oct 23 '22 15:10

gaetanoM