我想使用 map() 函数过滤一组项目。这是一个代码Fragments:
1 2 3 4 5 6 7
| var filteredItems = items.map(function(item)
{
if( ...some condition... )
{
return item;
}
}); |
问题是过滤掉的项目仍然使用数组中的空间,我想完全清除它们。
有什么想法吗?
编辑:谢谢,我忘了filter(),我想要的实际上是一个filter(),然后是一个map()。
EDIT2:感谢您指出 map() 和 filter() 并非在所有浏览器中都实现,尽管我的特定代码不打算在浏览器中运行。
你应该使用 filter 方法而不是 map 除非你想改变数组中的项目,除了过滤。
例如。
1 2 3 4
| var filteredItems = items.filter(function(item)
{
return ...some condition...;
}); |
[编辑:当然,您总是可以对过滤和变异执行 sourceArray.filter(...).map(...)]
受写这个答案的启发,我后来扩展并写了一篇博客文章,详细讨论了这个问题。如果您想更深入地了解如何考虑这个问题,我建议您检查一下——我尝试逐条解释,并在最后给出一个 JSperf 比较,考虑速度。
也就是说,** tl;dr 是这样的:
要完成您的要求(在一个函数调用中进行过滤和映射),您将使用 Array.reduce()**。
然而,更易读且(不太重要)通常明显更快的方法是仅使用链接在一起的过滤器和映射:
[1,2,3].filter(num = num 2).map(num = num * 2)
以下是对 Array.reduce() 工作原理的描述,以及如何使用它在一次迭代中完成过滤和映射。同样,如果这太浓缩了,我强烈建议您查看上面链接的博客文章,这是一个更友好的介绍,带有清晰的示例和进展。
你给 reduce 一个参数,它是一个(通常是匿名的)函数。
那个匿名函数有两个参数——一个(就像传入 map/filter/forEach 的匿名函数)是要操作的迭代对象。然而,传递给 reduce 的匿名函数还有另一个参数,即那些函数不接受,这就是将在函数调用之间传递的值,通常称为备忘录。
注意,虽然 Array.filter() 只接受一个参数(一个函数),但 Array.reduce() 还接受一个重要的(尽管是可选的)第二个参数:\\'memo\\' 的初始值,它将被传递到该匿名函数作为其第一个参数,随后可以在函数调用之间进行变异和传递。 (如果未提供,则第一个匿名函数调用中的 \\'memo\\' 默认为第一个 iteratee,而 \\'iteratee\\' 参数实际上是数组中的第二个值)
在我们的例子中,我们将传入一个空数组开始,然后根据我们的函数选择是否将我们的迭代器注入到我们的数组中——这就是过滤过程。
最后,我们将在每个匿名函数调用中返回我们的"正在处理的数组",reduce 将获取该返回值并将其作为参数(称为 memo)传递给它的下一个函数调用。
这允许过滤器和映射在一次迭代中发生,将我们所需的迭代次数减少了一半——虽然每次迭代只做两倍的工作,所以除了函数调用之外什么都没有真正保存,而函数调用并非如此在javascript中很昂贵。
有关更完整的解释,请参阅 MDN 文档(或此答案开头引用的我的帖子)。
Reduce 调用的基本示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| 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
| [1,2,3].reduce((memo, value) = value 1 ? memo.concat(value * 2) : memo, []) |
请注意,第一个 iteratee 不大于 1,因此被过滤掉了。还要注意 initialMemo,命名只是为了明确它的存在并引起人们的注意。再次,它作为 \\'memo\\' 传递给第一个匿名函数调用,然后匿名函数的返回值作为 \\'memo\\' 参数传递给下一个函数。
memo 的另一个经典用例示例是返回数组中的最小或最大数字。示例:
1 2
| [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 函数的示例(我发现这通常有助于理解这些函数):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| 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]);
// or, more technically complete, give access to base array
// and index to the reducer as well:
// memo = reduceFunc(memo, this[i], i, this);
}
// after we've compressed the array into a single value,
// we return it.
return memo;
} |
例如,真正的实现允许访问诸如索引之类的东西,但我希望这可以帮助您对它的要点有一个简单的感觉。
这不是地图的作用。你真的想要Array.filter。或者,如果您真的想从原始列表中删除元素,您将需要使用 for 循环强制执行此操作。
数组过滤方法
1 2 3 4 5 6 7 8 9
| 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 ) |
TLDR:使用 map(需要时返回 undefined),然后使用 filter.
首先,我认为地图过滤器功能很有用,因为您不想在两者中重复计算。 Swift 最初将此函数称为 flatMap,但后来将其重命名为 compactMap.
例如,如果我们没有 compactMap 函数,我们最终可能会定义两次 computation:
1 2 3 4 5 6 7 8 9 10 11 12 13
| let array = [1, 2, 3, 4, 5, 6, 7, 8];
let mapped = array
.filter(x = {
let computation = x / 2 + 1;
let isIncluded = computation % 2 === 0;
return isIncluded;
})
.map(x = {
let computation = x / 2 + 1;
return `${x} is included because ${computation} is even`
})
// Output: [2 is included because 2 is even, 6 is included because 4 is even] |
因此 compactMap 将有助于减少重复代码。
类似于 compactMap 的一个非常简单的方法是:
在实际值或 undefined 上映射。
过滤掉所有 undefined 值。
这当然依赖于您永远不需要返回未定义的值作为原始映射函数的一部分。
示例:
1 2 3 4 5 6 7 8 9 10 11 12
| let array = [1, 2, 3, 4, 5, 6, 7, 8];
let mapped = array
.map(x = {
let computation = x / 2 + 1;
let isIncluded = computation % 2 === 0;
if (isIncluded) {
return `${x} is included because ${computation} is even`
} else {
return undefined
}
})
.filter(x = typeof x !=="undefined") |
您必须注意,并非所有浏览器都支持 Array.filter,因此,您必须原型化:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| //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;
};
} |
这样做,您可以为您可能需要的任何方法制作原型。
首先你可以使用 map 和链式你可以使用 filter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| state.map(item = {
if(item.id === action.item.id){
return {
id : action.item.id,
name : item.name,
price: item.price,
quantity : item.quantity-1
}
}else{
return item;
}
}).filter(item = {
if(item.quantity = 0){
return false;
}else{
return true;
}
}); |
我刚刚写了正确处理重复的数组交集
https://gist.github.com/gkucmierz/8ee04544fa842411f7553ef66ac2fcf0
1 2 3 4 5 6 7 8 9 10 11 12 13
| // array intersection that correctly handles also duplicates
const intersection = (a1, a2) = {
const cnt = new Map();
a2.map(el = cnt[el] = el in cnt ? cnt[el] + 1 : 1);
return a1.filter(el = el in cnt && 0 cnt[el]--);
};
const l = console.log;
l(intersection('1234'.split``, '3456'.split``)); // [ '3', '4' ]
l(intersection('12344'.split``, '3456'.split``)); // [ '3', '4' ]
l(intersection('1234'.split``, '33456'.split``)); // [ '3', '4' ]
l(intersection('12334'.split``, '33456'.split``)); // [ '3', '3', '4' ] |
以下语句使用 map 函数清理对象。
1 2 3
| var arraytoclean = [{v:65, toberemoved:"gronf"}, {v:12, toberemoved:null}, {v:4}];
arraytoclean.map((x,i)=x.toberemoved=undefined);
console.dir(arraytoclean); |