Reputation: 2286
I am trying to filter an array by compare it to another array and return an element that is missing from the second array.
The same element may occur multiple times, and each occurrence should either have a corresponding occurrence in the second array or be considered missing from the second array.
Here is an example.
example 1:
const participant = ['mario', 'zelda', 'ken', 'sonic'];
const completion = ['zelda', 'ken', 'mario'];
// return 'sonic' because the name is not inside of completion array
example 2:
const participant = ['mario', 'zelda', 'ken', 'sonic'];
const completion = ['mario', 'ken', 'sonic'];
// return 'zelda', the name is not inside of the array
example 3:
const participant = ['mario', 'zelda', 'ken', 'mario'];
const completion = ['mario', 'zelda', 'ken'];
// this time return 'mario' because only one 'mario' is inside of the array (think of this as another person with the same name)
And this is how I try to solve it
// iteration participant array inside completion array and if completion array find first same element inside participant array, remove that element
const solution = (participant, completion) => {
completion.find(c => {
participant.forEach((p, idx) => {
if (c === p) {
participant.splice(idx, idx+1)
}
})
})
}
However this code only works in example 1 and 2, example 3 returns an empty array.
Thought using find method finds first element inside of an array that matches with element I want to find but it does not work way I expected.
Did I misuse find method?
Upvotes: 2
Views: 66
Reputation: 50807
Mea culpa. I didn't read the question closely enough. Here is another version
const removeEl = (xs, e, index = xs.indexOf(e)) =>
index < 0 ? xs : [... xs .slice (0, index), ... xs .slice (index + 1)]
const removeAll = (xs = [], [e = undefined, ...es] = []) =>
e == undefined ? xs : removeAll (removeEl(xs, e), es)
console.log(removeAll (['mario', 'zelda', 'ken', 'sonic'], ['zelda', 'ken', 'mario']))
console.log(removeAll (['mario', 'zelda', 'ken', 'sonic'], ['mario', 'ken', 'sonic']))
console.log(removeAll (['mario', 'zelda', 'ken', 'mario'], ['mario', 'zelda', 'ken']))
removeEl
returns a new array like the original but with the first copy of the given element removed.
removeAll
recursively calls itself for each element to be removed, using removeEl
to create the list it passes to the recursive call.
If you have really long lists to remove, then we should do an imperative loop in place of the recursion, as JS recursion depths restrictions are limiting here. But if you don't, this is fairly elegant, and it's available for tail call optimization if that ever becomes a reality in JS.
I think it's easier than what you're trying. How about this?:
const diff = (as, bs) => as.filter(a => !bs.includes(a)) const participant = ['mario', 'zelda', 'ken', 'sonic']; const completion = ['zelda', 'ken', 'mario']; console .log (diff (participant, completion))
Upvotes: 2
Reputation: 147256
You can use Array.findIndex
to find any value in completion
that is also in participant
and delete it from that array. This will only delete the first occurrence of the value in participant
, giving the correct result for your third example:
const solution = (participant, completion) => {
completion.forEach(c => {
idx = participant.findIndex(p => p == c);
if (idx >= 0) {
participant.splice(idx, idx + 1)
}
});
return participant;
};
let participant = ['mario', 'zelda', 'ken', 'sonic'];
let completion = ['zelda', 'ken', 'mario'];
console.log(solution(participant, completion));
participant = ['mario', 'zelda', 'ken', 'sonic'];
completion = ['mario', 'ken', 'sonic'];
console.log(solution(participant, completion));
participant = ['mario', 'zelda', 'ken', 'mario'];
completion = ['mario', 'zelda', 'ken'];
console.log(solution(participant, completion));
Upvotes: 3