使用JavaScript中的Array.map去除元素
我想通过使用map()
函数过滤一个项目的数组。 这是一个代码片段:
var filteredItems = items.map(function(item) { if( ...some condition... ) { return item; } });
问题是过滤出来的项目仍然使用数组中的空间,我想完全清除它们。
任何想法?
编辑:谢谢,我忘了filter()
,我想要的其实是一个filter()
然后一个map()
。
编辑2:感谢指出map()
和filter()
没有在所有浏览器中实现,虽然我的具体代码不打算在浏览器中运行。
您应该使用filter
方法,而不是映射,除非要过滤数组中的项目。
例如。
var filteredItems = items.filter(function(item) { return ...some condition...; });
[编辑:当然,你总是可以做sourceArray.filter(...).map(...)
来过滤和mutate]
其实,接受的答案是让你变得很短暂。 你真的想要使用减less,一个拉:
http://elijahmanor.com/reducing-filter-and-map-down-to-reduce/
但是,所以我不只是把链接,这是简短的版本。
你减less了一个(通常是匿名的)函数的参数。
这个匿名函数需要两个参数 – 一个(像传递给map / filter / forEach的匿名函数)是要操作的迭代器。 还有另外一个参数可以传递给匿名函数来减less这些函数不接受的值,这些函数调用之间的值通常被称为备忘录 。
请注意,虽然Array.filter()只接受一个参数(一个函数),但是Array.reduce()也需要一个重要的(尽pipe是可选的)第二个参数:“备忘录”的初始值将被传递给匿名函数第一个参数,随后可以在函数调用之间进行变异和传递。 (如果没有提供,那么第一个匿名函数调用中的“备忘录”默认是第一个迭代,而“iteratee”实际上是数组中的第二个值)
在我们的例子中,我们将传入一个空数组来开始,然后根据我们的函数select是否将我们的iteratee注入到数组中 – 这是过滤过程。
最后,我们将在每个匿名函数调用中返回我们的“正在进行的数组”,reduce将接受该返回值并将其作为参数(称为备忘录)传递给其下一个函数调用。
这允许filter和映射在一次迭代中发生,将我们需要的迭代次数减半。 🙂
有关更完整的解释,请参阅MDN或上面的链接。 🙂
减less呼叫的基本示例:
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, [])
请注意,第一个迭代不超过一个,所以被过滤。 还要注意initialMemo,这个名字只是为了让它的存在变得清晰并且引起注意。 再一次,它被作为“备忘录”传递给第一个匿名函数调用,然后匿名函数的返回值作为“备忘录”parameter passing给下一个函数。
备忘录的经典用例的另一个例子是返回数组中最小或最大的数字。 例:
[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 passed in two arguments, then our first memo value // will be whatever is in index zero. (Otherwise, it will // be that second argument.) const initialMemoIsIndexZero = arguments.length > 1; // here we use that logic to set the memo value accordingly. let memo = initialMemoIsIndexZero ? initialMemo : this[0]; // 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; }
我没有彻底地testing这个实现,只是把它写下来,但在我的两个基本的testing用例中,它似乎工作。 例如,真正的实现允许访问像索引这样的东西,但我希望这可以帮助您获得简单的感觉。
这不是地图。 你真的想要Array.filter 。 或者,如果您真的想从原始列表中删除元素,则需要使用for循环来执行此操作。
但是必须注意的是,所有的浏览器都不支持Array.filter
,所以你必须原型化:
//This prototype is provided by the Mozilla foundation and //is distributed under the MIT license. //http://www.ibiblio.org/pub/Linux/LICENSES/mit.license if (!Array.prototype.filter) { Array.prototype.filter = function(fun /*, thisp*/) { var len = this.length; if (typeof fun != "function") throw new TypeError(); var res = new Array(); var thisp = arguments[1]; for (var i = 0; i < len; i++) { if (i in this) { var val = this[i]; // in case fun mutates this if (fun.call(thisp, val, i, this)) res.push(val); } } return res; }; }
这样做,您可以为任何可能需要的方法build立原型。
var arr = [1,2,'xxx','yyy'] arr = arr.filter(function(e){ return e != 'xxx' }); arr // [1, 2, "yyy"]
我将这个答案放在这里,因为这个页面上共享的polyfills是糟糕的
function reduce(f, y, xs, context) { var acc = y; for (var i = 0, len = xs.length; i < len; i++) acc = f.call(context, acc, xs[i], i, xs); return acc; } function reduce1(f, xs, context) { if (xs.length === 0) throw Error('cannot reduce empty array without initial value'); else return reduce(f, xs[0], xs.slice(1), context); } function map(f, xs, context) { return reduce(function(acc, x, i) { return acc.concat([ f.call(context, x, i, xs) ]); }, [], xs); } function filter(f, xs, context) { return reduce(function(acc, x, i) { if (f.call(context, x, i, xs)) return acc.concat([x]); else return acc; }, [], xs); }
扩展原型
if (Array.prototype.reduce === undefined) { Array.prototype.reduce = function(f, initialValue, context) { if (initialValue === undefined) return reduce1(f, this, context); else return reduce(f, initialValue, this, context); }; } if (Array.prototype.map === undefined) { Array.prototype.map = function(f, context) { return map(f, this, context); }; } if (Array.prototype.filter === undefined) { Array.prototype.filter = function(f, context) { return filter(f, this, context); }; }