Come trovare il primo elemento dell’array che corrisponde a una condizione booleana in JavaScript?

Mi chiedo se esiste un modo conosciuto, integrato / elegante per trovare il primo elemento di un array JS che corrisponde a una determinata condizione. L’equivalente di AC # sarebbe List.Find .

Finora ho usato una combinazione a due funzioni come questa:

// 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 poi posso usare:

 var result = someArray.findFirst(isNotNullNorUndefined); 

Ma dal momento che ci sono tanti metodi di array in stile funzionale in ECMAScript , forse c’è già qualcosa di simile? Immagino che molte persone debbano implementare cose del genere tutto il tempo …

Dal momento che ES6 esiste il metodo di find nativo per gli array.


Devo pubblicare una risposta per interrompere questi suggerimenti sui filter 🙂

dal momento che ci sono tanti metodi di array in stile funzionale in ECMAScript, forse c’è già qualcosa del genere in questo modo?

È ansible utilizzare il metodo Array per iterare l’array fino a quando non viene soddisfatta una condizione (e quindi interrompere). Sfortunatamente restituirà solo se la condizione è stata soddisfatta una volta, non da quale elemento (o a quale indice) è stato raggiunto. Quindi dobbiamo modificarlo un po ‘:

 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 partire da ECMAScript 6, è ansible utilizzare Array.prototype.find per questo. Questo è implementato e funziona in Firefox (25.0), Chrome (45.0), Edge (12) e Safari (7.1), ma non in Internet Explorer o in una serie di altre piattaforms vecchie o non comuni .

Ad esempio, l’espressione seguente valuta 106 .

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

Se vuoi usarlo subito ma hai bisogno di supporto per IE o altri browser non supportati, puoi usare uno shim. Raccomando l’ es6-shim . MDN offre anche uno shim se per qualche motivo non si desidera inserire l’intero es6-shim nel progetto. Per la massima compatibilità si desidera es6-shim, perché a differenza della versione MDN rileva implementazioni native buggy di find e le sovrascrive (vedere il commento che inizia “Work around bug in Array # find and Array # findIndex” e le righe immediatamente successive ).

Che ne dici di usare il filtro e ottenere il primo indice dall’array risultante?

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

A questo punto dovrebbe essere chiaro che JavaScript non offre alcuna soluzione in modo nativo; ecco i due derivati ​​più vicini, il primo più utile:

  1. Array.prototype.some(fn) offre il comportamento desiderato di arresto quando viene soddisfatta una condizione, ma restituisce solo se un elemento è presente; non è difficile applicare alcuni trucchi, come la soluzione offerta dalla risposta di Bergi .

  2. Array.prototype.filter(fn)[0] un ottimo one-liner ma è il meno efficiente, perché butti via elementi N - 1 solo per ottenere ciò di cui hai bisogno.

I metodi di ricerca tradizionali in JavaScript sono caratterizzati dalla restituzione dell’indice dell’elemento trovato anziché dell’elemento stesso o -1. Questo evita di dover scegliere un valore di ritorno dal dominio di tutti i possibili tipi; un indice può essere solo un numero e i valori negativi non sono validi.

Entrambe le soluzioni di cui sopra non supportano la ricerca offset, quindi ho deciso di scrivere questo:

 (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 utilizzi underscore.js puoi utilizzare le funzioni find e indexOf per ottenere esattamente ciò che desideri:

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

Documentazione:

A partire da ES 2015, Array.prototype.find() fornisce questa funzionalità esatta.

Per i browser che non supportano questa funzione, Mozilla Developer Network ha fornito un polyfill (incollato di seguito):

 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 () fa proprio questo, maggiori informazioni: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find

Sommario:

  • Per trovare il primo elemento in un array che corrisponde a una condizione booleana possiamo usare ES6 find()
  • find() si trova su Array.prototype quindi può essere utilizzato su ogni array.
  • find() effettua una richiamata in cui viene verificata una condizione boolean . La funzione restituisce il valore (non l’indice!)

Esempio:

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

Non esiste alcuna funzione incorporata in Javascript per eseguire questa ricerca.

Se si utilizza jQuery, è ansible eseguire un jQuery.inArray(element,array) .

Un modo meno elegante che genererà tutti i giusti messaggi di errore (basati su Array.prototype.filter ) ma interromperà l’iterazione sul primo risultato

 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; } } 

Quindi gli esempi sono

 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 

Funziona chiudendo il filter usando throw .