437 votes

Comment trouver le premier élément d'un tableau correspondant à une condition booléenne en JavaScript ?

Je me demande s'il existe un moyen connu, intégré/élégant de trouver le premier élément d'un tableau JS correspondant à une condition donnée. Un équivalent en C# serait Liste.Rechercher .

Jusqu'à présent, j'ai utilisé un combo à deux fonctions comme celui-ci :

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

Et puis je peux utiliser :

var result = someArray.findFirst(isNotNullNorUndefined);

Mais comme il y a tant de méthodes de tableau de style fonctionnel dans ECMAScript peut-être existe-t-il déjà quelque chose de ce genre ? J'imagine que beaucoup de gens doivent mettre en œuvre des trucs comme ça tout le temps...

6 votes

Il n'y a pas de méthode intégrée, mais il existe des bibliothèques utilitaires qui se rapprochent de cette fonctionnalité, telles que documentcloud.github.com/underscore

0 votes

Underscore.js est en effet très joli ! Et il a find(). Merci !

1 votes

Juste pour que vous sachiez, vous pouvez réduire ça : return (typeof (o) !== 'undefined' && o !== null); à ceci return o != null; . Ils sont exactement équivalents.

516voto

Bergi Points 104242

Depuis ES6, il y a l'option native find méthode pour les tableaux ; cela arrête d'énumérer le tableau une fois qu'il a trouvé la première correspondance et retourne la valeur.

const result = someArray.find(isNotNullNorUndefined);

Vieille réponse :

Je dois poster une réponse pour arrêter ces filter suggestions :-)

Comme il existe de nombreuses méthodes de tableau de style fonctionnel dans l'ECMAScript, peut-être existe-t-il déjà quelque chose de ce type ?

Vous pouvez utiliser le some Méthode des tableaux pour itérer le tableau jusqu'à ce qu'une condition soit remplie (et ensuite s'arrêter). Malheureusement, elle ne retournera que si la condition a été remplie une fois, et non par quel élément (ou à quel index) elle a été remplie. Nous devons donc la modifier un peu :

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

37 votes

Je ne peux pas dire que je comprends entièrement toute l'aversion dirigée vers filter(). Il est peut-être plus lent, mais en réalité, dans la plupart des cas où il est probablement utilisé, il s'agit d'une petite liste pour commencer, et la majorité des applications JavaScript ne sont pas assez compliquées pour vraiment se soucier de l'efficacité à ce niveau. [].filter(test).pop() ou [].filter(test)[0] sont simples, natives et lisibles. Bien entendu, je parle ici d'applications professionnelles ou de sites web, et non d'applications intensives comme les jeux.

14 votes

Les solutions de filtrage traversent-elles tous les tableaux/collections ? Si c'est le cas, le filtrage est très inefficace, car il parcourt tout le tableau même si la valeur trouvée est la première de la collection. some() par contre, renvoie immédiatement, ce qui est beaucoup plus rapide dans presque tous les cas que les solutions de filtrage.

0 votes

AlikElzin-kilaka : Oui, exactement.

137voto

Mark Amery Points 4705

A partir d'ECMAScript 6, vous pouvez utiliser Array.prototype.find pour ça. Ceci est implémenté et fonctionne dans Firefox (25.0), Chrome (45.0), Edge (12), et Safari (7.1), mais pas dans Internet Explorer ou un tas d'autres plateformes anciennes ou peu courantes .

Par exemple, x ci-dessous est 106 :

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

Si vous voulez l'utiliser dès maintenant mais que vous avez besoin de la prise en charge d'IE ou d'autres navigateurs non pris en charge, vous pouvez utiliser une cale. Je recommande la es6-shim . MDN propose également une cale si pour une raison quelconque vous ne voulez pas mettre l'ensemble de la es6-shim dans votre projet. Pour une compatibilité maximale, il faut utiliser la version es6-shim, car contrairement à la version MDN, elle détecte les implémentations natives boguées de find et les écrase (voir le commentaire qui commence par "Contourner les bogues dans Array#find et Array#findIndex". et les lignes qui le suivent immédiatement).

1 votes

find est meilleur que filter depuis find s'arrête immédiatement lorsqu'il trouve un élément correspondant à la condition, tandis que filter Boucle à travers tous les éléments pour donner tous les éléments appariés.

83voto

Phil Mander Points 352

Et si on utilisait filtre et obtenir le premier indice du tableau résultant ?

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

8 votes

Continuez à utiliser les méthodes es5. var result = someArray.filter(isNotNullNorUndefined).shift() ;

1 votes

Bien que j'aie moi-même voté pour la réponse ci-dessus @Bergi, je pense qu'avec la déstructuration ES6 nous pouvons améliorer un peu la réponse ci-dessus : v

1 votes

@someyoungideas pourriez vous expliquer l'avantage d'utiliser .shift par ici ?

17voto

Jack Points 88446

Il devrait être clair maintenant que JavaScript n'offre pas une telle solution en natif ; voici les deux dérivés les plus proches, le plus utile en premier :

  1. Array.prototype.some(fn) offre le comportement souhaité, à savoir s'arrêter lorsqu'une condition est remplie, mais ne renvoie que si un élément est présent ; il n'est pas difficile d'appliquer quelques astuces, telles que la solution proposée par La réponse de Bergi .

  2. Array.prototype.filter(fn)[0] c'est une bonne phrase, mais c'est la moins efficace, car on jette N - 1 éléments juste pour obtenir ce dont vous avez besoin.

Les méthodes de recherche traditionnelles en JavaScript se caractérisent par le fait qu'elles renvoient l'index de l'élément trouvé au lieu de l'élément lui-même ou -1. Cela évite de devoir choisir une valeur de retour dans le domaine de tous les types possibles ; un index ne peut être qu'un nombre et les valeurs négatives ne sont pas valables.

Les deux solutions ci-dessus ne supportent pas non plus la recherche de décalage, j'ai donc décidé d'écrire ceci :

(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

0 votes

Il semble que la réponse soit la plus complète. Pouvez-vous ajouter la troisième approche dans votre réponse ?

10voto

Matt Woelk Points 345

Si vous utilisez underscore.js vous pouvez utiliser son find y indexOf pour obtenir exactement ce que vous voulez :

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

Documentation :

1 votes

Utilisez l'option underscorejs uniquement si c'est nécessaire, car charger une bibliothèque juste pour cela ne vaut pas la peine.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X