[英]How to find first element of array matching a boolean condition in JavaScript?
I'm wondering if there's a known, built-in/elegant way to find the first element of a JS array matching a given condition.我想知道是否有一种已知的、内置/优雅的方法来查找与给定条件匹配的 JS 数组的第一个元素。 AC# equivalent would be List.Find .
AC# 等效项是List.Find 。
So far I've been using a two-function combo like this:到目前为止,我一直在使用这样的双功能组合:
// 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);
};
And then I can use:然后我可以使用:
var result = someArray.findFirst(isNotNullNorUndefined);
But since there are so many functional-style array methods in ECMAScript , perhaps there's something out there already like this?但是既然ECMAScript 中有这么多函数式的数组方法,也许已经有这样的东西了? I imagine lots of people have to implement stuff like this all the time...
我想很多人必须一直实现这样的东西......
Since ES6 there is the native find
method for arrays;从 ES6 开始,数组就有了原生的
find
方法; this stops enumerating the array once it finds the first match and returns the value.一旦找到第一个匹配项并返回值,这将停止枚举数组。
const result = someArray.find(isNotNullNorUndefined);
Old answer:旧答案:
I have to post an answer to stop these filter
suggestions :-)我必须发布一个答案来停止这些
filter
建议:-)
since there are so many functional-style array methods in ECMAScript, perhaps there's something out there already like this?
既然 ECMAScript 中有这么多函数式数组方法,也许已经有这样的东西了?
You can use the some
Array method to iterate the array until a condition is met (and then stop).您可以使用
some
Array 方法迭代数组,直到满足条件(然后停止)。 Unfortunately it will only return whether the condition was met once, not by which element (or at what index) it was met.不幸的是,它只会返回条件是否满足一次,而不是由哪个元素(或在什么索引处)满足。 So we have to amend it a little:
所以我们要稍微修改一下:
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;
}
var result = find(someArray, isNotNullNorUndefined);
As of ECMAScript 6, you can use Array.prototype.find
for this.从 ECMAScript 6 开始,您可以为此使用
Array.prototype.find
。 This is implemented and working in Firefox (25.0), Chrome (45.0), Edge (12), and Safari (7.1), but not in Internet Explorer or a bunch of other old or uncommon platforms .这是在 Firefox (25.0)、Chrome (45.0)、Edge (12) 和 Safari (7.1) 中实现和工作的,但不适用于 Internet Explorer 或其他一些旧的或不常见的平台。
For example, x
below is 106
:例如,下面的
x
是106
:
const x = [100,101,102,103,104,105,106,107,108,109].find(function (el) { return el > 105; }); console.log(x);
If you want to use this right now but need support for IE or other unsupporting browsers, you can use a shim.如果您现在想使用它但需要支持 IE 或其他不支持的浏览器,您可以使用 shim。 I recommend the es6-shim .
我推荐es6-shim 。 MDN also offers a shim if for some reason you don't want to put the whole es6-shim into your project.
如果出于某种原因您不想将整个 es6-shim 放入您的项目中,MDN 还提供了一个 shim 。 For maximum compatibility you want the es6-shim, because unlike the MDN version it detects buggy native implementations of
find
and overwrites them (see the comment that begins "Work around bugs in Array#find and Array#findIndex" and the lines immediately following it).为了获得最大的兼容性,你想要的ES6-垫片,因为不像MDN版本,它检测到车机实现
find
,并覆盖它们(请参阅开始“工作周围的错误在阵列#查找和阵列#findIndex”注释和行紧随其后)。
使用过滤器并从结果数组中获取第一个索引怎么样?
var result = someArray.filter(isNotNullNorUndefined)[0];
ES6
find()
ES6
find()
find()
is located on Array.prototype
so it can be used on every array. find()
位于Array.prototype
因此它可以用于每个数组。find()
takes a callback where a boolean
condition is tested. find()
接受一个测试boolean
条件的回调。 The function returns the value (not the index!) const array = [4, 33, 8, 56, 23]; const found = array.find(element => { return element > 50; }); console.log(found); // 56
It should be clear by now that JavaScript offers no such solution natively;现在应该很清楚 JavaScript 本身没有提供这样的解决方案。 here are the closest two derivatives, the most useful first:
这是最接近的两个导数,最有用的第一个:
Array.prototype.some(fn)
offers the desired behaviour of stopping when a condition is met, but returns only whether an element is present; Array.prototype.some(fn)
提供在满足条件时停止的期望行为,但仅返回元素是否存在; it's not hard to apply some trickery, such as the solution offered by Bergi's answer .应用一些技巧并不难,例如Bergi's answer提供的解决方案。
Array.prototype.filter(fn)[0]
makes for a great one-liner but is the least efficient, because you throw away N - 1
elements just to get what you need. Array.prototype.filter(fn)[0]
是一个很好的单行代码,但效率最低,因为你扔掉N - 1
元素只是为了得到你需要的。
Traditional search methods in JavaScript are characterized by returning the index of the found element instead of the element itself or -1. JavaScript 中传统搜索方法的特点是返回找到的元素的索引而不是元素本身或 -1。 This avoids having to choose a return value from the domain of all possible types;
这避免了必须从所有可能类型的域中选择返回值; an index can only be a number and negative values are invalid.
索引只能是数字,负值无效。
Both solutions above don't support offset searching either, so I've decided to write this:上面的两个解决方案都不支持偏移搜索,所以我决定写这个:
(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
If you're using underscore.js
you can use its find
and indexOf
functions to get exactly what you want:如果您使用
underscore.js
您可以使用它的find
和indexOf
函数来准确获取您想要的内容:
var index = _.indexOf(your_array, _.find(your_array, function (d) {
return d === true;
}));
Documentation:文档:
As of ES 2015, Array.prototype.find()
provides for this exact functionality.从 ES 2015 开始,
Array.prototype.find()
提供了这个确切的功能。
For browsers that do not support this feature, the Mozilla Developer Network has provided a polyfill (pasted below):对于不支持此功能的浏览器,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;
};
}
foundElement = myArray[myArray.findIndex(element => //condition here)];
Array.prototype.find() 就是这样做的,更多信息: https : //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
Use findIndex
as other previously written.使用
findIndex
作为其他以前编写的。 Here's the full example:这是完整的示例:
function find(arr, predicate) {
foundIndex = arr.findIndex(predicate);
return foundIndex !== -1 ? arr[foundIndex] : null;
}
And usage is following (we want to find first element in array which has property id === 1
).用法如下(我们想在数组中找到属性
id === 1
第一个元素)。
var firstElement = find(arr, e => e.id === 1);
I have got inspiration from multiple sources on the internet to derive into the solution below.我从互联网上的多个来源获得灵感,得出以下解决方案。 Wanted to take into account both some default value and to provide a way to compare each entry for a generic approach which this solves.
希望同时考虑一些默认值并提供一种方法来比较每个条目以获得解决的通用方法。
Usage: (giving value "Second")用法:(赋予值“第二”)
var defaultItemValue = { id: -1, name: "Undefined" };
var containers: Container[] = [{ id: 1, name: "First" }, { id: 2, name: "Second" }];
GetContainer(2).name;
Implementation:执行:
class Container {
id: number;
name: string;
}
public GetContainer(containerId: number): Container {
var comparator = (item: Container): boolean => {
return item.id == containerId;
};
return this.Get<Container>(this.containers, comparator, this.defaultItemValue);
}
private Get<T>(array: T[], comparator: (item: T) => boolean, defaultValue: T): T {
var found: T = null;
array.some(function(element, index) {
if (comparator(element)) {
found = element;
return true;
}
});
if (!found) {
found = defaultValue;
}
return found;
}
There is no built-in function in Javascript to perform this search. Javascript 中没有内置函数来执行此搜索。
If you are using jQuery you could do a jQuery.inArray(element,array)
.如果你使用 jQuery,你可以做一个
jQuery.inArray(element,array)
。
A less elegant way that will throw
all the right error messages (based on Array.prototype.filter
) but will stop iterating on the first result is将
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;
}
}
Then examples are然后例子是
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
It works by ending filter
by using throw
.它通过使用
throw
结束filter
来工作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.