admin管理员组文章数量:1200396
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 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)
Share
Improve this question
edited Nov 26, 2019 at 17:57
vahdet
asked Nov 26, 2019 at 12:12
vahdetvahdet
6,72910 gold badges61 silver badges114 bronze badges
3
- Does this answer your question? How to get the difference between two arrays in JavaScript? – Juhil Somaiya Commented Nov 26, 2019 at 12:23
- Realize the “one go” is contextual. In the answer and question example, the use of “includes” is doing a lookup (internal loop) with each iteration of the expressed loop. In no case would there ever be a “one go” solution. – vol7ron Commented Nov 26, 2019 at 15:38
- @JuhilSomaiya Nope, I edited and added another use case to show that it is not always the difference of arrays with similar structure. – vahdet Commented Nov 26, 2019 at 17:59
6 Answers
Reset to default 7If 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);
Another (newer and slightly shorter) option is to use Object.groupBy
:
const arr = ['a', 'b', 'c', 'd', 'e'];
const cond = ['a', 'b'];
const { fi, fo } = Object.groupBy(arr, e => cond.includes(e) ? "fi" : "fo");
console.log(fi, fo);
Note: The returned arrays may be undefined instead of empty (or both if the input array is empty).
I could not destruct but this seems to be simpler to read than the reduce offered elsewhere
const myArray = ['a', 'b', 'c', 'd', 'e']
const filterArray = ['a', 'b']
let filteredOutResult = [];
const filteredInResult = myArray.filter(item => {
if (filterArray.includes(item)) return item;
filteredOutResult.push(item);
});
console.log(filteredInResult,filteredOutResult)
A solution with ramda's partition.
const
array = ['a', 'b', 'c', 'd', 'e'],
filter = ['a', 'b'],
[filteredInResult, filteredOutResult] = R.partition(v => filter.includes(v), array);
console.log(...filteredInResult); // a b
console.log(...filteredOutResult) // c d e
<script src="http://cdn.jsdelivr.net/ramda/latest/ramda.min.js"></script>
One native answer is to use Array#reduce
:
const { in, out } = myArr.reduce((acc, v) => {
(filterArray.includes(v) ? acc.in : acc.out).push(v);
return acc;
}, { in: [], out: [] });
And then destructure the returned object
本文标签: How to get filtered in and out elements of array at one go in JavascriptStack Overflow
版权声明:本文标题:How to get filtered in and out elements of array at one go in Javascript - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1738535045a2094361.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论