过滤和映射在相同的迭代
我有这种简单的情况,我想筛选和映射到相同的值,如下所示:
const files = results.filter(function(r){ return r.file; }) .map(function(r){ return r.file; });
为了节省代码行数,以及提高性能,我正在寻找:
const files = results.filterAndMap(function(r){ return r.file; });
这是否存在,或者我应该自己写点什么? 我在一些地方想要这样的function,以前从来没有打扰过这个function。
如果你真的需要在1个函数中做,你需要像这样使用reduce
results.reduce( // add the file name to accumulator if it exists (acc, result) => result.file ? acc.concat([result.file]) : acc, // pass empty array for initial accumulator value [] )
如果你需要挤出更多的性能,你可以改变concat
来push
并返回原始的累加器数组,以避免创build额外的数组。
然而,最快的解决scheme可能是一个很好的旧for
循环,避免所有的函数调用和堆栈帧
files = [] for (var i = 0; i < results.length; i++) { var file = results[i].file if (file) files.push(file) }
但是我认为filter/map
方法更具performance力和可读性
传感器
在其最一般的forms中,你的问题的答案在于换能器 。 但是在我们抽象之前,先来看一些基础知识 – 下面我们实现一个传感器mapReduce
, filterReduce
和tapReduce
; 你可以添加任何你需要的。
const mapReduce = map => reduce => (acc, x) => reduce (acc, map (x)) const filterReduce = filter => reduce => (acc, x) => filter (x) ? reduce (acc, x) : acc const tapReduce = tap => reduce => (acc, x) => (tap (x), reduce (acc, x)) const tcomp = (f,g) => k => f (g (k)) const concat = (xs,ys) => xs.concat(ys) const transduce = (...ts) => xs => xs.reduce (ts.reduce (tcomp, k => k) (concat), []) const main = transduce ( tapReduce (x => console.log('with:', x)), filterReduce (x => x.file), tapReduce (x => console.log('has file:', x.file)), mapReduce (x => x.file), tapReduce (x => console.log('final:', x))) const data = [{file: 1}, {file: undefined}, {}, {file: 2}] console.log (main (data)) // with: { file: 1 } // has file: 1 // final: 1 // with: { file: undefined } // with: {} // with: { file: 2 } // has file: 2 // final: 2 // => [ 1, 2 ]
为了提高性能,你必须测量什么解决scheme会更快。 让我们玩一下https://jsperf.com/filter-than-map-or-reduce/1
任何其他testing用例都是受欢迎的
如果你想玩基准对NodeJS(记得npm i benchmark
)
var suite = new (require('benchmark')).Suite function getSampleInput() { return [{file: 'foo'}, {other: 'bar'}, {file: 'baz'}, {file: 'quux'}, {other: 'quuxdoo'}, {file: 'foobar'}, {file: 'foo'}, {other: 'bar'}, {file: 'baz'}, {file: 'quux'}, {other: 'quuxdoo'}, {file: 'foobar'}, {file: 'foo'}, {other: 'bar'}, {file: 'baz'}, {file: 'quux'}, {other: 'quuxdoo'}, {file: 'foobar'}, {file: 'foo'}, {other: 'bar'}, {file: 'baz'}, {file: 'quux'}, {other: 'quuxdoo'}, {file: 'foobar'}, {file: 'foo'}, {other: 'bar'}, {file: 'baz'}, {file: 'quux'}, {other: 'quuxdoo'}, {file: 'foobar'}, {file: 'foo'}, {other: 'bar'}, {file: 'baz'}, {file: 'quux'}, {other: 'quuxdoo'}, {file: 'foobar'}, {file: 'foo'}, {other: 'bar'}, {file: 'baz'}, {file: 'quux'}, {other: 'quuxdoo'}, {file: 'foobar'}, {file: 'foo'}, {other: 'bar'}, {file: 'baz'}, {file: 'quux'}, {other: 'quuxdoo'}, {file: 'foobar'}] } // author https://stackoverflow.com/users/3716153/gaafar function reduce(results) { return results.reduce( (acc, result) => result.file ? acc.concat([result.file]) : acc , [] ) } // author https://stackoverflow.com/users/1223975/alexander-mills function filterThanMap(results) { return results.filter(function(r){ return r.file; }) .map(function(r){ return r.file; }); } // author https://stackoverflow.com/users/5361130/ponury-kostek function forEach(results) { const files = []; results.forEach(function(r){ if(r.file) files.push(r.file); }); return files } suite .add('filterThanMap', function() {filterThanMap(getSampleInput())}) .add('reduce', function() {reduce(getSampleInput())}) .add('forEach', function() {forEach(getSampleInput())}) .on('complete', function() { console.log('results:') this.forEach(function(result) { console.log(result.name, result.count, result.times.elapsed) }) console.log('the fastest is', this.filter('fastest').map('name')[0]) }) .run()
为什么不只是forEach
?
const files = []; results.forEach(function(r){ if(r.file) { files.push(r.file); } });
您可以使用o.file
或concat的值和一个空数组作为结果。
results.reduce((r, o) => r.concat(o.file || []), []);
你可以使用Array.prototype.reduce()
const results = [{file:{file:1}}, {notfile:{file:1}}]; const files = results.reduce(function(arr, r){ return r.file ? arr = [...arr, r.file.file] : arr; }, []); console.log(files); // 1
const file = (array) => { return array.reduce((acc,curr) => curr.file ? acc.concat(curr) : acc, []) }
过程:
acc初始化为[](空数组)。 减less文档