在 JavaScript 中使用 Array.map 删除元素

我想使用 map()函数过滤一个项目数组:

var filteredItems = items.map(function(item)
{
if( ...some condition... )
{
return item;
}
});

问题是,过滤掉的项目仍然使用数组中的空间,我想完全消除它们。

知道吗?

编辑: 谢谢,我忘了 filter(),我想要的其实是 filter(),然后是 map()

编辑2: 感谢指出 map()filter()并非在所有浏览器中都实现,尽管我的特定代码并不打算在浏览器中运行。

168136 次浏览

地图不是这样的。你真的想要 Array.filter。或者,如果真的想从原始列表中删除元素,则需要使用 for 循环执行此操作。

除了筛选之外,您还应该使用 filter方法而不是 map,除非您希望对数组中的项进行变异。

eg.

var filteredItems = items.filter(function(item)
{
return ...some condition...;
});

[编辑: 当然你总是可以做 sourceArray.filter(...).map(...)过滤和变异]

但是你必须注意,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;
};
}

And doing so, you can prototype any method you may need.

数组 Filter method

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 )

受到写这个答案的启发,我最终扩展并写了一篇博客文章仔细研究这个问题。如果您想更深入地理解如何思考这个问题,我推荐使用 checking that out——我尝试逐段解释它,并在最后给出 JSPERF 比较,讨论速度方面的考虑。

That said, **The tl;dr is this:

要完成您要求的任务(在一个函数调用中进行筛选和映射) ,可以使用 Array.reduce() * * 。

然而,更易读 还有(不太重要) 通常要快得多2方法只是使用过滤器和映射链接在一起:

[1,2,3].filter(num => num > 2).map(num => num * 2)

下面是对 Array.reduce()如何工作的描述,以及如何使用它在一次迭代中完成过滤和映射。同样,如果这篇文章过于简短,我强烈建议看看上面链接的博客文章,这是一篇友好得多的介绍,有清晰的例子和进展。


给出 reduce 参数,它是一个(通常是匿名的)函数。

这个匿名函数 有两个参数——一个(就像传递给 map/filter/forEach 的匿名函数一样)是要操作的迭代器。但是,传递给 reduce 的匿名函数还有另一个参数,即 将在函数调用之间传递的值,通常称为 < em > note ,这些函数不接受该参数。

请注意,虽然 Array.filter ()只有一个参数(一个函数) ,但是 Array.reduce ()也有一个重要的(尽管是可选的)第二个参数: 一个‘ Note’的初始值,它将作为第一个参数传递给该匿名函数,随后可以在函数调用之间进行变异和传递。(如果没有提供,那么默认情况下,第一个匿名函数调用中的‘ note’将是第一个迭代器,而‘ iteratee’参数实际上将是数组中的第二个值)

In our case, we'll pass in an empty array to start, and then choose whether to inject our iteratee into our array or not based on our function--this is the filtering process.

最后,我们将在每个匿名函数调用上返回“正在进行中的数组”,reduce 将获取该返回值,并将其作为参数(称为 note)传递给下一个函数调用。

这使得过滤器和映射可以在一次迭代中完成,从而将我们需要的迭代次数减少了一半——尽管每次迭代只需要完成两倍的工作,所以除了函数调用之外,没有其他任何东西可以保存,而函数调用在 javascript 中并不是那么昂贵。

要获得更完整的解释,请参考 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, [])

注意,第一个迭代器不大于1,因此被过滤了。还要注意首字母 Memo,它的命名只是为了让它的存在更加清晰,并引起人们的注意。再一次,它作为‘ note’传递给第一个匿名函数调用,然后匿名函数的返回值作为‘ note’参数传递给下一个函数。

另一个备忘录经典用例的例子是返回数组中最小或最大的数字。例如:

[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]);
// 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;
}

例如,真正的实现允许访问索引之类的内容,但是我希望这有助于您对索引的要点有一个简单的了解。

下面的语句使用 map 函数清除对象。

var arraytoclean = [{v:65, toberemoved:"gronf"}, {v:12, toberemoved:null}, {v:4}];
arraytoclean.map((x,i)=>x.toberemoved=undefined);
console.dir(arraytoclean);

I just wrote array intersection that correctly handles also duplicates

Https://gist.github.com/gkucmierz/8ee04544fa842411f7553ef66ac2fcf0

// 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' ]

首先你可以使用地图和链接,你可以使用过滤器

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;
}
});

TLDR: 使用 map(需要时返回 undefined)和 那么 filter


First, I believe that a map + filter function is useful since you don't want to repeat a computation in both. Swift originally called this function flatMap but then renamed it to compactMap.

例如,如果我们没有 compactMap函数,我们可能最终定义了两次 computation:

  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的事情的一个非常简单的方法是:

  1. 映射到实际值或 undefined
  2. 过滤掉所有的 undefined值。

当然,这取决于您永远不需要返回未定义的值作为原始 map 函数的一部分。

例如:

  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")