Como encontrar o primeiro elemento de array correspondente a uma condição booleana em JavaScript?
até agora tenho usado uma combinação de duas funções como esta:
// 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);
};
e depois posso usar:
var result = someArray.findFirst(isNotNullNorUndefined);
mas já que existem tantos métodos de matriz funcional em ECMAScript, talvez já haja algo por aí como isto? Imagino que muita gente tenha de implementar coisas. sempre assim...
10 answers
find
Método para matrizes.
Eu tenho que postar uma resposta para parar estas filter
sugestões: -)
Como há tantos métodos de matriz funcional em ECMAScript, talvez já haja algo assim?
Pode usar o some
método Array para iterar o array até que uma condição seja cumprida (e então parar). Infelizmente, só voltará a verificar se a condição foi cumprida uma vez., não com que elemento (ou em que índice) foi satisfeito. Por isso, temos de O alterar um pouco.
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;
}
A partir do ECMAScript 6, pode utilizar Array.prototype.find
por isto. Isto é implementado e trabalhando no Firefox (25.0), Chrome (45.0), Edge (12), e Safari (7.1), mas não no Internet Explorer ou um monte de outras plataformas antigas ou incomuns.
Por exemplo, a expressão abaixo avalia-se em 106
.
[100,101,102,103,104,105,106,107,108,109].find(function (el) {
return el > 105;
});
Se quiser usar isto agora, mas precisar de suporte para o IE ou outros navegadores sem suporte, pode usar um shim. Recomendo o es6-shim. MDN também oferece Um shim, se por alguma razão não quiseres colocar todo o es6-shim no teu projecto. Para a compatibilidade máxima, você quer o es6-shim, porque ao contrário da versão MDN, ele detecta implementações nativas buggy de find
e os reescreve (veja o comentário que começa "trabalhar em torno de bugs na lista#find and Array#findIndex" e as linhas imediatamente a seguir).
Que tal usar o filtro e obter o primeiro índice da matriz resultante?
var result = someArray.filter(isNotNullNorUndefined)[0];
Já deve estar claro que o JavaScript não oferece tal solução nativamente; Aqui estão as duas derivadas mais próximas, as mais úteis primeiro:
Array.prototype.some(fn)
oferece o comportamento desejado de parar quando uma condição é cumprida, mas retorna apenas se um elemento está presente; não é difícil aplicar algumas artimanhas, como a solução oferecida pela resposta de Bergi.Array.prototype.filter(fn)[0]
faz para um grande one-liner, mas é o menos eficiente, porque você joga foraN - 1
elementos apenas para obter o que você precisa.
Os métodos tradicionais de pesquisa em JavaScript são caracterizados por devolver o índice do elemento encontrado em vez do próprio elemento ou -1. Isso evita ter que escolher um valor de retorno do domínio de todos os tipos possíveis; um índice só pode ser um número e os valores negativos são inválidos.
Ambas as soluções acima também não suportam a procura por offset, por isso decidi escrever isto:
(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
Se estiver a utilizar {[1] } pode usar as suas funções find
e indexOf
para obter exactamente o que quer:
var index = _.indexOf(your_array, _.find(your_array, function (d) {
return d === true;
}));
Documentação:
A partir de ES 2015, Array.prototype.find()
prevê esta funcionalidade exacta.
Para navegadores que não suportam esta funcionalidade, a rede de desenvolvimento do Mozilla forneceu um polifill (colado abaixo):
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;
};
}
Matriz.prototipo.find () does just that, more info: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
Resumo:
- para encontrar o primeiro elemento numa matriz que corresponda a uma condição booleana, podemos usar o
ES6
find()
-
find()
está localizado em {[4] } para que possa ser usado em todos os array. -
find()
faz um callback onde uma condiçãoboolean
é testada. A função devolve o valor (não o índice!)
Exemplo:
const array = [4, 33, 8, 56, 23];
const found = array.find((element) => {
return element > 50;
});
console.log(found); // 50
Não existe nenhuma função incorporada no Javascript para realizar esta pesquisa.
Se estiver a usar jQuery, pode fazer um jQuery.inArray(element,array)
.
Uma forma menos elegante que irá throw
todas as mensagens de erro certas (com base em Array.prototype.filter
) mas vai parar de iterar no primeiro resultado é
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;
}
}
Então os exemplos são
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
Funciona terminando filter
usando throw
.