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

我想使用该函数过滤项目数组。下面是一个代码片段:map()

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

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

有什么想法吗?

编辑:谢谢,我忘了,我想要的实际上是一个然后。filter()filter()map()

EDIT2:感谢您指出这一点,并且并非所有浏览器都实现了这一点,尽管我的特定代码并不打算在浏览器中运行。map()filter()


答案 1

除了筛选之外,还应使用该方法而不是 map,除非要更改数组中的项。filter

例如。

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

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


答案 2

受撰写此答案的启发,我后来扩展并撰写了一篇博客文章,详细讨论了这个问题。如果你想更深入地了解如何思考这个问题,我建议你检查一下 - 我试图一点一点地解释它,并在最后给出一个JSperf比较,包括速度考虑。

也就是说,**tl;dr是这样的:

若要完成所需的内容(在一个函数调用中进行筛选和映射),请使用 **。Array.reduce()

但是,可读性更强(不太重要)通常明显更快的2 方法是仅使用过滤器和地图链接在一起:

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

以下是对工作原理的描述,以及如何使用它在一次迭代中完成筛选和映射。同样,如果这太浓缩了,我强烈建议您查看上面链接的博客文章,这是一个更友好的介绍,其中包含清晰的示例和进度。Array.reduce()


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

该匿名函数采用两个参数 - 一个(如传递给map/filter/forEach的匿名函数)是要操作的迭代器。但是,对于为减少而传递的匿名函数,还有另一个参数,这些函数不接受,那就是将在函数调用之间传递的值,通常称为memo

请注意,虽然Array.filter()只接受一个参数(一个函数),但Array.reduce()也采用一个重要(尽管是可选的)第二个参数:'memo'的初始值,该值将作为其第一个参数传递到该匿名函数中,随后可以在函数调用之间进行突变和传递。(如果未提供,则默认情况下,第一个匿名函数调用中的“memo”将是第一个迭代器,而“iteratee”参数实际上是数组中的第二个值)

在我们的例子中,我们将传入一个空数组来启动,然后根据我们的函数选择是否将迭代注入数组 - 这是过滤过程。

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

这允许过滤器和映射在一次迭代中发生,将我们所需的迭代次数减少了一半 - 每次迭代只需做两倍的工作,所以除了函数调用之外,没有任何东西可以真正保存,这在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,命名只是为了使其存在清楚并引起人们对它的注意。再次,它作为“memo”传递给第一个匿名函数调用,然后匿名函数的返回值作为“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]);
        // 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;
}

例如,真正的实现允许访问索引之类的东西,但我希望这有助于您获得对它要点的简单感觉。