可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I would like to filter a collection using array of property value. Given an array of IDs, return objects with matching IDs. Is there any shortcut method using lodash
/underscore
?
var collections = [{ id: 1, name: 'xyz' },
{ id: 2, name: 'ds' },
{ id: 3, name: 'rtrt' },
{ id: 4, name: 'nhf' },
{ id: 5, name: 'qwe' }];
var ids = [1,3,4];
// This works, but any better way?
var filtered = _.select(collections, function(c){
return ids.indexOf(c.id) != -1
});
回答1:
If you're going to use this sort of pattern a lot, you could create a mixin like the following, though, it isn't doing anything fundementally different than your original code. It just makes it more developer friendly.
_.mixin({
'findByValues': function(collection, property, values) {
return _.filter(collection, function(item) {
return _.contains(values, item[property]);
});
}
});
Then you can use it like this.
var collections = [
{id: 1, name: 'xyz'},
{id: 2, name: 'ds'},
{id: 3, name: 'rtrt'},
{id: 4, name: 'nhf'},
{id: 5, name: 'qwe'}
];
var filtered = _.findByValues(collections, "id", [1,3,4]);
Update - This above answer is old and clunky. Please use the answer from Adam Boduch for a much more elegant solution.
_(collections)
.keyBy('id') // or .indexBy() if using lodash 3.x
.at(ids)
.value();
回答2:
A concise lodash solution that uses indexBy() and at().
_(collections)
.indexBy('id')
.at(ids)
.value();
回答3:
We can also filter like this
var collections = [{ id: 1, name: 'xyz' },
{ id: 2, name: 'ds' },
{ id: 3, name: 'rtrt' },
{ id: 4, name: 'nhf' },
{ id: 5, name: 'qwe' }];
var filtered_ids = _.filter(collections, function(p){
return _.includes([1,3,4], p.id);
});
console.log(filtered_ids);
回答4:
I like jessegavin's answer, but I expanded on it using lodash-deep for deep property matching.
var posts = [{ term: { name: 'A', process: '123A' } },
{ term: { name: 'B', process: '123B' } },
{ term: { name: 'C', process: '123C' } }];
var result = _.filterByValues(posts, 'term.process', ['123A', '123C']);
// results in objects A and C to be returned
jsFiddle
_.mixin({
'filterByValues': function(collection, key, values) {
return _.filter(collection, function(o) {
return _.contains(values, resolveKey(o, key));
});
}
});
function resolveKey(obj, key) {
return (typeof key == 'function') ? key(obj) : _.deepGet(obj, key);
}
If you don't trust lodash-deep or you want support for properties that have dots in their names, here's a more defensive and robust version:
function resolveKey(obj, key) {
if (obj == null || key == null) {
return undefined;
}
var resolved = undefined;
if (typeof key == 'function') {
resolved = key(obj);
} else if (typeof key == 'string' ) {
resolved = obj[key];
if (resolved == null && key.indexOf(".") != -1) {
resolved = _.deepGet(obj, key);
}
}
return resolved;
}
回答5:
I noticed many of these answers are outdated or contain auxiliary functions not listed in Lodash documentation. The accepted answer includes deprecated function _.contains
and should be updated.
So here is my ES6 answer.
Based on Lodash v4.17.4
_.mixin( {
filterByValues: ( c, k, v ) => _.filter(
c, o => _.indexOf( v, o[ k ] ) !== -1
)
} );
And invoked as such:
_.filterByValues(
[
{
name: 'StackOverflow'
},
{
name: 'ServerFault'
},
{
name: 'AskDifferent'
}
],
'name',
[ 'StackOverflow', 'ServerFault' ]
);
// => [ { name: 'StackOverflow' }, { name: 'ServerFault' } ]
回答6:
These answers didn't work for me, because I wanted to filter on a non-unique value. If you change keyBy
to groupBy
you can get by.
_(collections)
.groupBy(attribute)
.pick(possibleValues)
.values()
.flatten()
.value();
My initial use was to drop things, so I switched out pick
with omit
.
Thanks Adam Boduch for the starting point.
回答7:
This worked great for me:
let output = _.filter(collections, (v) => _.includes(ids, v.id));