我想通过使用该map()
函数来过滤项目数组.这是一段代码:
var filteredItems = items.map(function(item) { if( ...some condition... ) { return item; } });
问题是过滤掉的项目仍然使用数组中的空间,我想完全消除它们.
任何的想法?
编辑:谢谢,我忘了filter()
,我想要的实际上是filter()
一个map()
.
EDIT2:感谢您指出map()
并且filter()
并未在所有浏览器中实现,尽管我的特定代码并不打算在浏览器中运行.
filter
除了过滤之外,您应该使用方法而不是map,除非您想要改变数组中的项目.
例如.
var filteredItems = items.filter(function(item) { return ...some condition...; });
[编辑:当然你总是可以做sourceArray.filter(...).map(...)
过滤和变异]
我现在回答了一段时间,我的意见发生了变化.我建议查看我的博客文章,它扩展了这个主题并更好地解释了它.它还在替代方案的最后给出了JSperf比较.
tl; dr就是这样:要完成你所要求的(在一个函数调用中过滤和映射),你应该使用Array.reduce()
.然而,更可读 且 通常更快的2方法是仅使用链接和映射链接在一起:
[1,2,3].filter(num => num > 2).map(num => num * 2)
以下是对如何Array.reduce()
工作的描述,以及如何在一次迭代中使用它来完成过滤和映射.如果这太过浓缩,我强烈建议您查看上面链接的博客文章,这是一个更加友好的介绍,有清晰的示例和进展.
你给减少一个(通常是匿名的)函数的参数.
该匿名函数有两个参数 - 一个(如传入map/filter/forEach的匿名函数)是要操作的iteratee.然而,传递给reduce的匿名函数有另一个参数,即那些函数不接受,这是函数调用之间传递的值,通常称为备忘录.
请注意,虽然Array.filter()只接受一个参数(一个函数),但Array.reduce()也接受一个重要的(尽管是可选的)第二个参数:'memo'的初始值,它将作为其传递给该匿名函数第一个参数,随后可以在函数调用之间进行变异和传递.(如果没有提供,那么第一个匿名函数调用中的'memo'将默认为第一个iteratee,'iteratee'参数实际上将是数组中的第二个值)
在我们的例子中,我们将传入一个空数组来启动,然后根据我们的函数选择是否将我们的iteratee注入到我们的数组中 - 这是过滤过程.
最后,我们将在每个匿名函数调用中返回'正在进行的数组',reduce将获取该返回值并将其作为参数(称为memo)传递给它的下一个函数调用.
这允许过滤器和映射在一次迭代中发生,将我们所需的迭代次数减少一半.:)
有关更完整的说明,请参阅MDN或上面的链接.:)
Reduce调用的基本示例:
let array = [1,2,3]; const initialMemo = []; array = array.reduce((memo, iteratee) => { // if condition is our filter if (iteratee > 1) { // what happens inside the filter is the map memo.push(iteratee * 2); } // this return value will be passed in as the 'memo' argument // to the next call of this function, and this function will have // every element passed into it at some point. return memo; }, initialMemo) console.log(array) // [4,6], equivalent to [(2 * 2), (3 * 2)]
更简洁的版本:
[1,2,3].reduce((memo, value) => value > 1 ? memo.concat(value * 2) : memo, [])
请注意,第一个iteratee不大于1,因此被过滤.还要注意initialMemo,命名只是为了使其存在清晰并引起对它的注意.再一次,它作为'memo'传递给第一个匿名函数调用,然后匿名函数的返回值作为'memo'参数传递给下一个函数.
备忘录的经典用例的另一个例子是返回数组中最小或最大的数字.例:
[7,4,1,99,57,2,1,100].reduce((memo, val) => memo > val ? memo : val) // ^this would return the largest number in the list.
一个如何编写自己的reduce函数的例子(这通常有助于理解这些函数,我发现):
test_arr = []; // we accept an anonymous function, and an optional 'initial memo' value. test_arr.my_reducer = function(reduceFunc, initialMemo) { // if we did not pass in a second argument, then our first memo value // will be whatever is in index zero. (Otherwise, it will // be that second argument.) const initialMemoIsIndexZero = arguments.length < 2; // here we use that logic to set the memo value accordingly. let memo = initialMemoIsIndexZero ? this[0] : initialMemo; // here we use that same boolean to decide whether the first // value we pass in as iteratee is either the first or second // element const initialIteratee = initialMemoIsIndexZero ? 1 : 0; for (var i = initialIteratee; i < this.length; i++) { // memo is either the argument passed in above, or the // first item in the list. initialIteratee is either the // first item in the list, or the second item in the list. memo = reduceFunc(memo, this[i]); } // after we've compressed the array into a single value, // we return it. return memo; }
例如,真正的实现允许访问索引之类的东西,但我希望这可以帮助您获得简单的感觉.
这不是地图的作用.你真的想要Array.filter.或者如果你真的想从原始列表中删除元素,那么你需要使用for循环来强制执行它.
var arr = [1, 2, 3]
// ES5 syntax
arr = arr.filter(function(item){ return item != 3 })
// ES2015 syntax
arr = arr.filter(item => item != 3)
console.log( arr )