Zoeken op website

Hoe vind je het eerste element van een array dat voldoet aan een booleaanse voorwaarde in JavaScript?


Ik vraag me af of er een bekende, ingebouwde/elegante manier is om het eerste element van een JS-array te vinden dat aan een bepaalde voorwaarde voldoet. Een C#-equivalent zou List.Find zijn.

Tot nu toe heb ik een tweefunctie-combinatie zoals deze gebruikt:

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

En dan kan ik gebruiken:

var result = someArray.findFirst(isNotNullNorUndefined);

Maar aangezien er zoveel functionele array-methoden in ECMAScript zijn, is er misschien al zoiets beschikbaar? Ik kan me voorstellen dat veel mensen dit soort dingen de hele tijd moeten implementeren...

Antwoord #1

Sinds ES6 is er de native find methode voor arrays; dit stopt met het doorlopen van de array zodra het de eerste overeenkomst vindt en retourneert de waarde.

const result = someArray.find(isNotNullNorUndefined);

Oud antwoord:

Ik moet een antwoord plaatsen om deze filter suggesties te stoppen :-)

Aangezien er zoveel functionele array-methoden in ECMAScript zijn, is er misschien al iets dergelijks beschikbaar?

Je kunt de some Array-methode gebruiken om door de array te itereren totdat aan een voorwaarde is voldaan (en dan stoppen). Helaas geeft het alleen terug of aan de voorwaarde eenmaal is voldaan, niet door welk element (of op welke index) dit gebeurde. Dus we moeten het een beetje aanpassen:

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

Antwoord #2

Vanaf ECMAScript 6 kun je Array.prototype.find hiervoor gebruiken. Dit is geïmplementeerd en werkend in Firefox (25.0), Chrome (45.0), Edge (12) en Safari (7.1), maar niet in Internet Explorer of een heleboel andere oude of minder gebruikelijke platforms.

Bijvoorbeeld, x hieronder is 106:

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

Als je dit nu wilt gebruiken maar ondersteuning nodig hebt voor IE of andere niet-ondersteunende browsers, kun je een shim gebruiken. Ik raad de es6-shim aan. MDN biedt ook een shim aan als je om een of andere reden niet de hele es6-shim in je project wilt opnemen. Voor maximale compatibiliteit wil je de es6-shim, omdat deze, in tegenstelling tot de MDN-versie, buggy native implementaties van find detecteert en overschrijft (zie de opmerking die begint met “Work around bugs in Array#find and Array#findIndex” en de regels die er direct op volgen).

Antwoord #3

Wat dacht je van het gebruik van filter en het ophalen van de eerste index uit de resulterende array?

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

Antwoord #4

Samenvatting :

  • Om het eerste element in een array te vinden dat aan een booleaanse voorwaarde voldoet, kunnen we de ES6 find() gebruiken
  • find() bevindt zich op Array.prototype, zodat het op elk array kan worden gebruikt.
  • find() neemt een callback waarin een boolean-voorwaarde wordt getest. De functie retourneert de waarde (niet de index!)

Voorbeeld :

const array = [4, 33, 8, 56, 23];

const found = array.find(element => {
  return element > 50;
});

console.log(found);   //  56

Antwoord #5

Het zou nu duidelijk moeten zijn dat JavaScript van nature geen dergelijke oplossing biedt; hier zijn de twee dichtstbijzijnde afgeleiden, eerst de meest nuttige:

  1. Array.prototype.some(fn) biedt het gewenste gedrag van stoppen wanneer aan een voorwaarde is voldaan, maar retourneert alleen of een element aanwezig is; het is niet moeilijk om wat trucjes toe te passen, zoals de oplossing die in Bergi's antwoord wordt aangeboden.

  2. Array.prototype.filter(fn)[0] is een geweldige one-liner, maar is het minst efficiënt, omdat je N - 1 elementen weggooit alleen om te krijgen wat je nodig hebt.

Traditionele zoekmethoden in JavaScript worden gekenmerkt door het teruggeven van de index van het gevonden element in plaats van het element zelf of -1. Dit voorkomt dat men een returnwaarde moet kiezen uit het domein van alle mogelijke typen; een index kan alleen een nummer zijn en negatieve waarden zijn ongeldig.

Beide bovenstaande oplossingen ondersteunen ook geen offset-zoeken, dus ik heb besloten dit te schrijven:

(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

Antwoord #6

Als je underscore.js gebruikt, kun je de functies find en indexOf gebruiken om precies te krijgen wat je wilt:

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

Documentatie:

  • http://underscorejs.org/#find
  • http://underscorejs.org/#indexOf

Gerelateerde artikelen