如何在JavaScript中找到匹配布尔条件的数组的第一个元素?

Jak*_* P. 183 javascript arrays

我想知道是否有一种已知的,内置/优雅的方法来查找匹配给定条件的JS数组的第一个元素.AC#等价物将是List.Find.

到目前为止,我一直在使用这样的双功能组合:

// Returns the first element of an array that satisfies given predicate
Array.prototype.findFirst = function (predicateCallback) {
    if (typeof predicateCallback !== 'function') {
        return undefined;
    }

    for (var i = 0; i < arr.length; i++) {
        if (i in this && predicateCallback(this[i])) return this[i];
    }

    return undefined;
};

// Check if element is not undefined && not null
isNotNullNorUndefined = function (o) {
    return (typeof (o) !== 'undefined' && o !== null);
};
Run Code Online (Sandbox Code Playgroud)

然后我可以使用:

var result = someArray.findFirst(isNotNullNorUndefined);
Run Code Online (Sandbox Code Playgroud)

但是由于ECMAScript中存在如此多的函数式数组方法,或许还有类似的东西吗?我想很多人都要一直这样实现这样的东西......

Ber*_*rgi 175

从ES6开始,存在数组的本机find方法.


我必须发布一个答案来阻止这些filter建议:-)

因为在ECMAScript中有这么多功能样式的数组方法,或许已经有这样的东西了吗?

您可以使用someArray方法迭代数组,直到满足条件(然后停止).不幸的是,它只会返回条件是否满足一次,而不是通过哪个元素(或在什么索引处)满足.所以我们要修改一下:

const result = someArray.find(isNotNullNorUndefined);
Run Code Online (Sandbox Code Playgroud)

  • 不能说我完全理解所有针对filter()的不喜欢.它可能更慢,但实际上; 在大多数可能使用它的情况下,它是一个小的列表,并且大多数JavaScript应用程序都不够复杂,不足以真正担心这个级别的效率.[] .filter(test).pop()或[] .filter(test)[0]简单,原生且可读.当然,我说的是商业应用或网站,而不是游戏等密集型应用. (27认同)
  • @JoshMc肯定,但是当发布一个像Stack Overflow这样的简单问题的解决方案时,不要无偿地低效.很多人会将这里的代码复制并粘贴到实用程序函数中,其中一些人在某些情况下最终会在性能重要的环境中使用该实用程序函数而不考虑实现.如果你给他们一些开头有效的实现,你要么解决了他们原本没有的性能问题,要么为他们节省了大量的开发时间来诊断它. (13认同)
  • 过滤器解决方案是否遍历所有阵列/集合?如果是这样,过滤效率非常低,因为即使找到的值是集合中的第一个值,它也会遍历所有数组.另一方面,`some()`会立即返回,这几乎在所有情况下都比过滤解决方案快得多. (11认同)

Mar*_*ery 96

从ECMAScript 6开始,您可以使用Array.prototype.find它.这是在Firefox(25.0),Chrome(45.0),Edge(12)和Safari(7.1)中实现和使用的,但不适用于Internet Explorer或其他一些旧的或不常见的平台.

例如,下面的表达式求值为106.

[100,101,102,103,104,105,106,107,108,109].find(function (el) {
    return el > 105;
});
Run Code Online (Sandbox Code Playgroud)

如果您现在要使用此功能但需要支持IE或其他不支持的浏览器,则可以使用填充程序.我推荐es6-shim.如果由于某种原因您不想将整个es6-shim放入您的项目中,MDN也会提供垫片.为了获得最大的兼容性,你需要es6-shim,因为它与MDN版本不同,它检测错误的本机实现find并覆盖它们(请参阅开头的注释"解决Array#find和Array#findIndex中的错误"以及紧随其后的行) .


Phi*_*der 53

如何使用过滤器并从结果数组中获取第一个索引?

var result = someArray.filter(isNotNullNorUndefined)[0];
Run Code Online (Sandbox Code Playgroud)

  • @jakubiszon 使用 `shift` 的好处是它“看起来很聪明”,但实际上更令人困惑。谁会认为调用不带参数的“shift()”与获取第一个元素相同?国际海事组织还不清楚。无论如何,数组访问速度更快:https://jsperf.com/array-access-vs-shift (7认同)
  • 继续使用es5方法.var result = someArray.filter(isNotNullNorUndefined).shift(); (5认同)
  • `shift()`是es3. (3认同)
  • 虽然我本人赞成在 @Bergi 上面找到答案,但我认为通过 ES6 解构,我们可以在上面进行一点改进: var [result] = someArray.filter(isNotNullNorUndefined); (2认同)

Ja͢*_*͢ck 15

现在应该很清楚JavaScript本身没有提供这样的解决方案; 这里是最接近的两个衍生物,最有用的第一个:

  1. Array.prototype.some(fn)提供满足条件时所需的停止行为,但仅返回元素是否存在; 应用一些技巧并不难,比如Bergi的答案所提供的解决方案.

  2. Array.prototype.filter(fn)[0]是一个伟大的单线,但效率最低,因为你扔掉N - 1元素只是为了得到你需要的东西.

JavaScript中的传统搜索方法的特征在于返回找到的元素的索引而不是元素本身或-1.这避免了必须从所有可能类型的域中选择返回值; 索引只能是数字而负值无效.

上面的两个解决方案都不支持偏移搜索,所以我决定写这个:

(function(ns) {
  ns.search = function(array, callback, offset) {
    var size = array.length;

    offset = offset || 0;
    if (offset >= size || offset <= -size) {
      return -1;
    } else if (offset < 0) {
      offset = size - offset;
    }

    while (offset < size) {
      if (callback(array[offset], offset, array)) {
        return offset;
      }
      ++offset;
    }
    return -1;
  };
}(this));

search([1, 2, NaN, 4], Number.isNaN); // 2
search([1, 2, 3, 4], Number.isNaN); // -1
search([1, NaN, 3, NaN], Number.isNaN, 2); // 3
Run Code Online (Sandbox Code Playgroud)


Mat*_*elk 8

如果你正在使用,underscore.js你可以使用它findindexOf函数来获得你想要的东西:

var index = _.indexOf(your_array, _.find(your_array, function (d) {
    return d === true;
}));
Run Code Online (Sandbox Code Playgroud)

文档:


Wil*_*een 7

摘要:

  • 为了找到匹配布尔条件的数组中的第一个元素,我们可以使用 ES6 find()
  • find()位于上,Array.prototype因此可以在每个阵列上使用。
  • find()接受boolean测试条件的回调。该函数返回(不是索引!)

例:

const array = [4, 33, 8, 56, 23];

const found = array.find((element) => {
  return element > 50;
});

console.log(found);   //  56
Run Code Online (Sandbox Code Playgroud)

  • 如果您确实想要索引而不是值,请使用 [`findIndex`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex) (2认同)

Kev*_*ner 5

从 ES 2015 开始,Array.prototype.find()提供了这种确切的功能。

对于不支持此功能的浏览器,Mozilla 开发者网络提供了一个polyfill(粘贴在下面):

if (!Array.prototype.find) {
  Array.prototype.find = function(predicate) {
    if (this === null) {
      throw new TypeError('Array.prototype.find called on null or undefined');
    }
    if (typeof predicate !== 'function') {
      throw new TypeError('predicate must be a function');
    }
    var list = Object(this);
    var length = list.length >>> 0;
    var thisArg = arguments[1];
    var value;

    for (var i = 0; i < length; i++) {
      value = list[i];
      if (predicate.call(thisArg, value, i, list)) {
        return value;
      }
    }
    return undefined;
  };
}
Run Code Online (Sandbox Code Playgroud)