我想使用以下方法过滤一系列项目 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(...) 过滤和变异]

其他提示

前一段时间我写了一个答案,我的观点发生了变化。我建议查看我的 博客文章 它扩展了这个主题并更好地解释了它。它还在替代方案的末尾给出了 JSperf 比较。

tl;dr 是这样的:要完成您所要求的任务(在一个函数调用中过滤和映射),您应该使用 Array.reduce(). 。但是,那 更具可读性 通常更快2 方法是仅使用链接在一起的过滤器和映射:

[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)传递给下一个函数调用。

这允许过滤和映射在一次迭代中发生,将所需的迭代次数减少一半。:)

更完整的解释请参考 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”参数传递给下一个函数。

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

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

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

那不是地图的作用。你真的想要 数组过滤器. 。或者,如果您确实想从原始列表中删除元素,则需要使用 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;
    };
}

这样做,您可以对您可能需要的任何方法进行原型设计。

我将这个答案放在这里是因为此页面上共享的填充内容非常糟糕

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);
  };
}
var arr = [1,2,'xxx','yyy']

arr = arr.filter(function(e){ return e != 'xxx' });

arr  // [1, 2, "yyy"]
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top