1

I'm trying to filter out objects from array "a" that match with objects in array "b" and "c". here is a link to jsfiddle to test the code.

Here is what I currently have:

const a = [{
  "name": "sondre",
  "uq_id": "abc1"
}, {
  "name": "sofie",
  "uq_id": "abc2"
}, {
  "name": "casper",
  "uq_id": "abc3"
}, {
  "name": "odin",
  "uq_id": "abc4"
}];

const b = [{
  "name": "sondre",
  "uq_id": "abc1"
}, {
  "name": "odin",
  "uq_id": "abc4"
}];

const c = [{
  "name": "casper",
  "uq_id": "abc3"
}];

function sort(a, b, c) {
  result = [];
  console.log(result);
  if (b !== null) {
    result = a.filter(function(item) {
      return !b.includes(item.uq_id);
    })
  }
  if (c !== null) {
    result = result.filter(function(item) {
      return !c.includes(item.uq_id);
    })
  }
  console.log(result);
}

sort(a, b, c);

I expect the following output:

[{name="sofie", uq_id="abc2"}]

But for some reason it outputs:

[{name="sondre", uq_id="abc1"},
{name="sofie", uq_id="abc2"},
{name="casper", uq_id="abc3"},
{name="odin", uq_id="abc4"}]

Does anyone know how I can get this to work as I intended it?

3
  • 1
    "heres a link to jsfiddle to test the code" Please do your runnable example here, on-site using Stack Snippets (the [<>] toolbar button; here's how to do one). Commented Jul 8, 2019 at 10:53
  • Why is the function called sort? It doesn't do any sorting. Commented Jul 8, 2019 at 10:53
  • ^ indeed, it does more "filtering". Or rather intersection between three arrays. Commented Jul 8, 2019 at 10:54

3 Answers 3

2

If the goal is to filter out entries from a whose name matches an entry on either b or c, you can't use includes unless the entries in a, b, and c refer to the same objects (not just equivalent ones).

Assuming they don't, you can use some to find out whether an array contains a match for a name. You'll want to use && to see that there's no match in either b or c:

const filtered = a.filter(entry => {
    return !b.some(({name}) => entry.name === name) &&
           !c.some(({name}) => entry.name === name);
});

Live Copy:

const a = [{
  "name": "sondre",
  "uq_id": "abc1"
}, {
  "name": "sofie",
  "uq_id": "abc2"
}, {
  "name": "casper",
  "uq_id": "abc3"
}, {
  "name": "odin",
  "uq_id": "abc4"
}];

const b = [{
  "name": "sondre",
  "uq_id": "abc1"
}, {
  "name": "odin",
  "uq_id": "abc4"
}];

const c = [{
  "name": "casper",
  "uq_id": "abc3"
}];

function filter(a, b, c) {
    const filtered = a.filter(entry => {
        return !b.some(({name}) => entry.name === name) &&
               !c.some(({name}) => entry.name === name);
    });
    return filtered;
}

console.log(filter(a, b, c));

That can also be expressed with every, whichever you prefer:

const filtered = a.filter(entry => {
    return b.every(({name}) => entry.name !== name) &&
           c.every(({name}) => entry.name !== name);
});

If b and c are really large (hundreds of thousands of entries, perhaps millions) that could be inefficient enough to justify creating Sets of names first:

const names = new Set([
  ...b.map(({name}) => name),
  ...c.map(({name}) => name)
]);
const filtered = a.filter(entry => {
    return !names.has(entry.name);
});

Or you might just do that for preference or clarity.

Live Copy:

const a = [{
  "name": "sondre",
  "uq_id": "abc1"
}, {
  "name": "sofie",
  "uq_id": "abc2"
}, {
  "name": "casper",
  "uq_id": "abc3"
}, {
  "name": "odin",
  "uq_id": "abc4"
}];

const b = [{
  "name": "sondre",
  "uq_id": "abc1"
}, {
  "name": "odin",
  "uq_id": "abc4"
}];

const c = [{
  "name": "casper",
  "uq_id": "abc3"
}];

function filter(a, b, c) {
    const names = new Set([
      ...b.map(({name}) => name),
      ...c.map(({name}) => name)
    ]);
    const filtered = a.filter(entry => {
        return !names.has(entry.name);
    });
    return filtered;
}

console.log(filter(a, b, c));

Sign up to request clarification or add additional context in comments.

3 Comments

Apologies, I had a silly logic error (and typo) that I didn't catch until doing the runnable examples. :-/
How would this handle B or C being empty, undefined or null?
@SondreLjovshin - Empty isn't a problem. If they might be undefined or null, you'll want to handle that. Probably the easiest way is if (!b) { b = []; } if (!c) { c = []; } before you start the filtering.
1

b and c are arrays of objects it only includes objects. You need to use some() on then to compare uq_id

const a = [{
    "name": "sondre",
    "uq_id": "abc1"
}, {
    "name": "sofie",
    "uq_id": "abc2"
}, {
    "name": "casper",
    "uq_id": "abc3"
}, {
    "name": "odin",
    "uq_id": "abc4"
}];

const b = [{
    "name": "sondre",
    "uq_id": "abc1"
}, {
    "name": "odin",
    "uq_id": "abc4"
}];

const c = [{
    "name": "casper",
    "uq_id": "abc3"
}];

sort(a, b, c);



function sort(a, b, c) {
    let result = [];
    if (b !== null) {
        result = a.filter(function(item) {
            return !b.some(x => x.uq_id === item.uq_id);
        })
    }
    if (c !== null) {
        result = result.filter(function(item) {
            return !c.some(x => x.uq_id === item.uq_id);
        })
    }
    console.log(result);
}

1 Comment

Thank you for the answer, this seems to resolve my problem in the most efficient way
0

Single filter is enough :

const a = [ { "name": "sondre", "uq_id": "abc1" }, 
            { "name": "sofie" , "uq_id": "abc2" }, 
            { "name": "casper", "uq_id": "abc3" }, 
            { "name": "odin"  , "uq_id": "abc4" } ];

const b = [ { "name": "sondre", "uq_id": "abc1" }, 
            { "name": "odin"  , "uq_id": "abc4" } ];

const c = [ { "name": "casper", "uq_id": "abc3" } ];


const result = a.filter(x => !b.some(y => x.uq_id === y.uq_id) 
                          && !c.some(y => x.uq_id === y.uq_id));

console.log(result);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.