如何find在JavaScript中匹配布尔条件的数组的第一个元素?
我想知道是否有一个已知的,内置的/优雅的方式来查找匹配给定条件的JS数组的第一个元素。 AC#相当于List.Find 。
到目前为止,我一直在使用这样的双function组合:
// 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);
但是由于ECMAScript中有这么多的函数式数组方法 ,或许这里已经有了一些东西呢? 我想很多人不得不一直执行这样的东西…
由于ES6有数组的本地find
方法 。
我必须发布一个答案来阻止这些filter
build议:-)
因为ECMAScript中有很多函数式的数组方法,或许这里已经有这样的东西了?
您可以使用some
Array方法迭代数组,直到满足条件(然后停止)。 不幸的是,它只会返回一次是否满足条件,而不是由哪个元素(或者以什么指数)满足。 所以我们必须稍微修改一下:
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; }
从ECMAScript 6开始,可以使用Array.prototype.find
。 这是在Firefox(25.0),Chrome(45.0),Edge(12)和Safari(7.1)中实现和使用的,但不能在Internet Explorer或其他一些旧的或不常见的平台上使用 。
例如,下面的expression式评估为106
。
[100,101,102,103,104,105,106,107,108,109].find(function (el) { return el > 105; });
如果您现在想要使用此function,但需要支持IE或其他不支持的浏览器,则可以使用垫片。 我推荐es6垫片 。 如果由于某种原因,MDN也提供了一个垫片 ,你不想把整个es6垫片放到你的项目中。 为了达到最大的兼容性,你需要es6-shim,因为与MDN版本不同的是,它检测到bug的本地实现并覆盖它们(参见注释“解决Array#find和Array#findIndex中的错误”以及紧随其后的行)。
那么如何使用filter并从结果数组中获取第一个索引呢?
var result = someArray.filter(isNotNullNorUndefined)[0];
现在应该清楚的是,JavaScript本身不提供这样的解决scheme; 这里是最接近的两个派生物,最有用的第一个:
-
Array.prototype.some(fn)
提供了满足条件时停止的所需行为,但只返回元素是否存在; 应用一些欺骗手段并不困难,比如Bergi的答案提供的解决scheme。 -
Array.prototype.filter(fn)[0]
是一个很好的单线程,但效率最低,因为你扔掉N - 1
元素只是为了得到你所需要的。
JavaScript中的传统search方法的特点是返回find的元素的索引,而不是元素本身或-1。 这避免了必须从所有可能types的域中select返回值; 索引只能是一个数字,负值是无效的。
上面的两个解决scheme都不支持偏移search,所以我决定写这个:
(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
如果你使用的是underscore.js
你可以使用它的find
和indexOf
函数来得到你想要的:
var index = _.indexOf(your_array, _.find(your_array, function (d) { return d === true; }));
文档:
从ES 2015开始, Array.prototype.find()
提供了这个确切的function。
对于不支持此function的浏览器,Mozilla开发者networking提供了一个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; }; }
Array.prototype.find()就是这样,更多信息: https : //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
Javascript中没有内置函数来执行此search。
如果你正在使用jQuery,你可以做一个jQuery.inArray(element,array)
。
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
。