Как найти первый элемент массива, соответствующий логическому условию в JavaScript?
мне интересно, есть ли известный, встроенный / элегантный способ найти первый элемент массива JS, соответствующий заданному условию. Эквивалент C# будет список.Найти.
до сих пор я использовал комбинацию из двух функций, как это:
// 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, может быть, там уже есть что-то подобное? Я представляю себе много люди должны реализовывать такие вещи все время...
10 ответов:
так как ES6 есть родной
findметод для массивов.
Я должен отправить ответ, чтобы остановить эти
filterпожелания :-)поскольку в ECMAScript так много методов массива функционального стиля, возможно, что-то там уже есть?
можно использовать
someметод выбора для итерации массива до тех пор, пока условие не будет выполнено (а затем остановится). К сожалению, это будет возвращает только то, было ли условие выполнено один раз, а не каким элементом (или по какому индексу) оно было выполнено. Поэтому мы должны немного изменить его: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 или кучу других старых или необычных платформ.например, выражение ниже имеет значение
106.[100,101,102,103,104,105,106,107,108,109].find(function (el) { return el > 105; });если вы хотите использовать это прямо сейчас, но вам нужна поддержка IE или других неподдерживаемых браузеров, вы можете использовать прокладку. Я рекомендую es6-shim. MDN также предлагает клин если по какой-то причине вы не хотите помещать всю ES6-прокладку в свой проект. Для максимальной совместимости вы хотите es6-shim, потому что в отличие от версии MDN он обнаруживает багги собственных реализаций
findи перезаписывает их (см. комментарий, который начинается с "работа вокруг ошибок в массиве#найти и массив#findIndex" и строки сразу после него).
Как насчет использования фильтр и получение первого индекса из результирующего массива?
var result = someArray.filter(isNotNullNorUndefined)[0];
теперь должно быть ясно, что JavaScript не предлагает такого решения изначально; вот ближайшие две производные, наиболее полезные первые:
Array.prototype.some(fn)предлагает желаемое поведение остановки при выполнении условия, но возвращает только наличие элемента; нетрудно применить некоторые хитрости, такие как решение, предлагаемое ответ Берги.
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
если вы используете
underscore.jsможно использоватьfindиindexOfфункции, чтобы получить то, что вы хотите:var index = _.indexOf(your_array, _.find(your_array, function (d) { return d === true; }));документы:
по состоянию на ES 2015,
Array.prototype.find()обеспечивает эту точную функциональность.для браузеров, которые не поддерживают эту функцию, сеть разработчиков Mozilla предоставила полифилл (вставленный ниже):
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; }; }
массив.прототип.find () делает именно это, больше информации: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
резюме:
- для нахождения первого элемента в массиве, который соответствует логическому условию, мы можем использовать
ES6find()find()расположена наArray.prototypeтак что он может быть использован на каждом массиве.find()принимает обратный вызов, где abooleanусловие проверяется. Функция возвращает стоимостью (не Индекс!)пример:
const array = [4, 33, 8, 56, 23]; const found = array.find((element) => { return element > 50; }); console.log(found); // 50
в Javascript нет встроенной функции для выполнения этого поиска.
Если вы используете 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он работает по конец
filterС помощьюthrow.
Comments