首页 文章

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

提问于
浏览
139

我'm wondering if there'是一种已知的,内置/优雅的方法来查找匹配给定条件的JS数组的第一个元素 . C#等价物将是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);
};

然后我可以使用:

var result = someArray.findFirst(isNotNullNorUndefined);

但既然有so many functional-style array methods in ECMAScript,也许那里已经有类似的东西?我想很多人都要一直这样实现这样的东西......

10 回答

  • 15

    从ECMAScript 6开始,您可以使用Array.prototype.find . 这是在Firefox(25.0),Chrome(45.0),Edge(12)和Safari(7.1)中实现并运行的,但是not in Internet Explorer or a bunch of other old or uncommon platforms .

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

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

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

  • 128

    摘要:

    • 为了找到数组中与布尔条件匹配的第一个元素,我们可以使用 ES6 find()

    • find() 位于 Array.prototype ,因此可以在每个阵列上使用 .

    • find() 进行回调测试 boolean 条件 . 该函数返回 value (不是索引!)

    示例:

    const array = [4, 33, 8, 56, 23];
    
    const found = array.find((element) => {
      return element > 50;
    });
    
    console.log(found);   //  50
    
  • 2

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

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

    • 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
    
  • 51

    那么使用filter并从结果数组中获取第一个索引呢?

    var result = someArray.filter(isNotNullNorUndefined)[0];
    
  • -1

    自ES 2015起, Array.prototype.find() 提供了这一确切的功能 .

    对于不支持此功能的浏览器,Mozilla Developer Network提供了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;
      };
    }
    
  • 82

    Array.prototype.find()就是这么做的,更多信息:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find

  • 3

    Javascript中没有内置函数来执行此搜索 .

    如果你使用jQuery,你可以做 jQuery.inArray(element,array) .

  • -1

    从ES6开始,对于数组,存在本机find method .


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

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

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

    function find(arr, test, ctx) {
        var result = null;
        arr.some(function(el, i) {
            return test.call(ctx, el, i, arr) ? ((result = el), true) : false;
        });
        return result;
    }
    
  • 1

    一个不太优雅的方式将 throw 所有正确的错误消息(基于 Array.prototype.filter )但将停止迭代第一个结果是

    function findFirst(arr, test, context) {
        var Result = function (v, i) {this.value = v; this.index = i;};
        try {
            Array.prototype.filter.call(arr, function (v, i, a) {
                if (test(v, i, a)) throw new Result(v, i);
            }, context);
        } catch (e) {
            if (e instanceof Result) return e;
            throw e;
        }
    }
    

    然后是例子

    findFirst([-2, -1, 0, 1, 2, 3], function (e) {return e > 1 && e % 2;});
    // Result {value: 3, index: 5}
    findFirst([0, 1, 2, 3], 0);               // bad function param
    // TypeError: number is not a function
    findFirst(0, function () {return true;}); // bad arr param
    // undefined
    findFirst([1], function (e) {return 0;}); // no match
    // undefined
    

    它的工作原理是使用 throw 结束 filter .

  • 7

    如果您正在使用 underscore.js ,您可以使用其 findindexOf 函数来获得您想要的内容:

    var index = _.indexOf(your_array, _.find(your_array, function (d) {
        return d === true;
    }));
    

    文档:

相关问题