var list = [
{ mode: 1, type: 'foo', blah: 1 },
{ mode: 3, type: 'foo', blah: 1 },
{ mode: 3, type: 'foo', blah: 1 },
{ mode: 1, type: 'bar', blah: 1 },
{ mode: 2, type: 'bar', blah: 0 },
{ mode: 3, type: 'bar', blah: 1 }
];
var filter = [
{ propertyName: 'mode', value: 1 },
{ propertyName: 'type', value: 'foo' },
{ propertyName: 'blah', value: 1 }
];
var i = 0;
var result1 = $.grep(list, function(x){
i++;
return x.type === 'foo' && x.mode === 1 && x.blah === 1;
});
console.log(result1, 'iterations:', i); // 6 iterations
var j = 0;
var result2 = list;
$.each(filter, function(k, filter){
result2 = $.grep(result2, function(listItem) {
j++;
return listItem[filter.propertyName] === filter.value;
});
});
console.log(result2, 'iterations:', j); // 9 iterations
我想优化上面提供result2
的过滤方法。
正如您在result1
中所看到的,可以通过较少的迭代实现相同的结果。在我的示例中可能看起来不多,但是有大量列表,其中性能是一个问题。
我的问题:有没有办法优化result2
的过滤,以便它可以作为result1
过滤?
答案 0 :(得分:2)
你可以先建立一个匹配的对象,然后重复使用它来避免loop-de-loop:
var ob={};
filter.map(function(a,b){
ob[a.propertyName]=a.value;
})
result2 = $.grep(list, function(x){
j++;
return x.type === ob.tpye && x.mode === ob.mode && x.blah === ob.blah;
});
/* which has the console showing (and yes, they are the same two objects in both results):
[Object] "iterations:" 6
[Object] "iterations:" 6 */
答案 1 :(得分:1)
我的问题:有没有办法优化result2的过滤,以便它作为result1过滤工作?
是。 grep
正在为每个过滤器构建一个新数组,最好只执行一次。使用原生filter
和every
方法:
var result3 = list.filter(function(listItem) {
return filter.every(function(test) {
return listItem[test.propertyName] === test.value;
});
});
普通循环可能会更快。使用jQuery的迭代,它没有every
等价物,你无论如何都会使用它:
var result3 = $.grep(list, function(listItem) {
for (var i=0, l=filter.length; i<l; i++)
if (listItem[filter[i].propertyName] !== filter[i].value)
return false;
return true;
});
当然,每次仍然需要迭代filter
,你没有真正解决这个问题(除非你编译new Function
)。但是你可以通过放置那些将过滤掉前面大部分项目的属性来优化filter
数组。
编辑:这是一个带编译函数的例子:
var result4 = list.filter(new Function("listItem",
"return "+filter.map(function(test) {
return "listItem."+test.propertyName+"==="+JSON.stringify(test.value);
// make sure that ^ these are valid ^ these are primitive
// identifiers value only
}).join(" && ")+";"
));
然而,它的性能需要经过彻底的测试,因为评估函数体可能会带来巨大的开销,特别是在旧的JS引擎中。但是,对于数千个已过滤的行,它可能会更快。
答案 2 :(得分:0)
您可以将@dandavis和@Bergi之前的答案结合起来:
var filtered = list.filter(function(item) {
return filter.every(function(f) {
return f.value === item[f.propertyName];
});
});