I wonder if there is a precise way for getting filtered an unfiltered elements of an array in Javascript, I mean, like, in one go.
Currently, I use a logic like follows:
const myArray = ['a', 'b', 'c', 'd', 'e']
const filterArray = ['a', 'b']
// I want to combine those two expressions somehow
const filteredInResult = myArray.filter(e => filterArray.includes(e))
const filteredOutResult = myArray.filter(e => !filterArray.includes(e))
console.log(filteredInResult)
console.log(filteredOutResult)
I felt like a destructuring-like way might already be there to achieve it, but anyway, I prefer asking you guys if there is a way for getting filtered in & out results in one shot.
EDIT: SO keeps alerting me if this question is similar to the question here, but I used string comparison and includes
for brewity above but the filtering expression may be more complex than that. So, the I must underline that the focus of the question is not on difference of two string arrays. I am leaving another example and hope the questions won't be merged :D
// A more complex use case
const myArray = [
{id: 1, value: 'a'},
{id: 2, value: 'b'},
{id: 3, value: 'c'},
{id: 4, value: 'd'},
{id: 5, value: 'e'},
]
const filterArray = ['a', 'b']
// I want to combine those two expressions somehow
const filteredInResult = myArray.filter(e => filterArray.includes(e.value))
const filteredOutResult = myArray.filter(e => !filterArray.includes(e.value))
console.log(filteredInResult)
console.log(filteredOutResult)
If you're worried about iterating twice over the myArray
, you might first consider reducing the computational complexity. Because each iteration of the loops calls Array.prototype.includes
, and the complexity of Array.prototype.includes
is O(n)
, your code has an overall complexity of O(n ^ 2)
. (outer loop: O(n)
* inner loop: O(n)
). So, consider fixing that first: use a Set and Set.has
, an O(1)
operation, instead of an array and .includes
. This is assuming that your actual filterArray
is large enough that computational complexity is something to worry about - sets do have a bit of an overhead cost.
As for the other (main) part of the question, one option is to create the two result arrays outside, then push to the appropriate one while iterating:
const myArray = ['a', 'b', 'c', 'd', 'e']
const filterArray = new Set(['a', 'b'])
const filteredInResult = [];
const filteredOutResult = [];
for (const e of myArray) {
(filterArray.has(e) ? filteredInResult : filteredOutResult).push(e);
}
console.log(filteredInResult)
console.log(filteredOutResult)
Could also use reduce
, though I don't think it looks very good:
const myArray = ['a', 'b', 'c', 'd', 'e']
const filterArray = new Set(['a', 'b'])
const { filteredInResult, filteredOutResult } = myArray.reduce((a, e) => {
a[filterArray.has(e) ? 'filteredInResult' : 'filteredOutResult'].push(e);
return a;
}, { filteredInResult: [], filteredOutResult: [] });
console.log(filteredInResult)
console.log(filteredOutResult)
You could use .reduce()
instead of .filter()
, where you use the (numeric) boolean value of includes()
as the index for your accumilator like so:
const myArray = ['a', 'b', 'c', 'd', 'e'];
const filterArray = ['a', 'b'];
const [fOut, fIn] = myArray.reduce((a, n) => {
a[+filterArray.includes(n)].push(n);
return a;
}, [[], []]);
console.log(fIn);
console.log(fOut);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With