Je me demande s’il existe un moyen connu, intégré et élégant de trouver le premier élément d’un tableau JS correspondant à une condition donnée. Un équivalent C # serait List.Find .
Jusqu'ici, 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 puisqu'il y a tant de méthodes de tableaux de style fonctionnel dans ECMAScript , il y a peut-être déjà quelque chose comme ça? J'imagine que beaucoup de gens doivent mettre en œuvre des choses comme ça tout le temps ...
Depuis ES6, il existe la méthode native find
pour les tableaux.
const result = someArray.find(isNotNullNorUndefined);
Je dois poster une réponse pour arrêter ces suggestions de filter
:-)
puisqu'il y a tellement de méthodes de tableaux de style fonctionnel dans ECMAScript, il y a peut-être déjà quelque chose comme ça?
Vous pouvez utiliser la méthode de tableau some
jusqu'à ce qu'une condition soit remplie (puis s'arrête). Malheureusement, il ne retournera que si la condition a été remplie une fois, pas par quel élément (ou à quel index) elle a été remplie. Nous devons donc le 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);
A partir de ECMAScript 6, vous pouvez utiliser Array.prototype.find
pour cela. 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 vieux ou peu communs plates-formes .
Par exemple, l'expression ci-dessous est évaluée à _106
_.
_[100,101,102,103,104,105,106,107,108,109].find(function (el) {
return el > 105;
});
_
Si vous voulez utiliser ceci maintenant mais que vous avez besoin de support pour IE ou d'autres navigateurs non pris en charge, vous pouvez utiliser un shim. Je recommande le es6-shim . MDN propose également ne cale si, pour une raison quelconque, vous ne souhaitez pas intégrer la totalité de es6-cession à votre projet. Es6-shim, pour une compatibilité maximale, car contrairement à la version MDN, il détecte les implémentations natives erronées de find
et les écrase (voir le commentaire qui commence "Contournez les bogues dans Array #find and Array # findIndex " et les lignes qui le suivent immédiatement).
Qu'en est-il d'utiliser filter et d'obtenir le premier index du tableau résultant?
var result = someArray.filter(isNotNullNorUndefined)[0];
Il devrait être clair maintenant que JavaScript n'offre pas une telle solution de manière native; voici les deux dérivés les plus proches, le plus utile en premier:
Array.prototype.some(fn)
offre le comportement souhaité d'arrêt lorsqu'une condition est remplie, mais renvoie uniquement si un élément est présent; il n'est pas difficile d'appliquer des astuces, comme la solution proposée par réponse de Bergi .
Array.prototype.filter(fn)[0]
constitue un excellent choix sur une ligne mais est le moins efficace, car vous jetez N - 1
éléments uniquement pour obtenir ce dont vous avez besoin.
Les méthodes de recherche traditionnelles en JavaScript sont caractérisées par le renvoi de l'index de l'élément trouvé à la place 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 valides.
Les deux solutions ci-dessus ne supportent pas la recherche offset, donc j'ai 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
Si vous utilisez underscore.js
, vous pouvez utiliser ses fonctions find
et indexOf
pour obtenir exactement ce que vous voulez:
var index = _.indexOf(your_array, _.find(your_array, function (d) {
return d === true;
}));
Documentation:
ES6
find()
find()
est situé sur Array.prototype
afin qu'il puisse être utilisé sur chaque tableau.find()
prend un rappel où une condition boolean
est testée. La fonction retourne le valeur (pas l'index!)const array = [4, 33, 8, 56, 23];
const found = array.find((element) => {
return element > 50;
});
console.log(found); // 56
À compter de l'ES 2015, Array.prototype.find()
fournit cette fonctionnalité exacte.
Pour les navigateurs qui ne prennent pas en charge cette fonctionnalité, le réseau de développeurs Mozilla a fourni un polyfill (collé ci-dessous):
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 () fait justement cela, plus d’informations: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find
Je me suis inspiré de multiples sources sur Internet pour trouver la solution ci-dessous. Je voulais prendre en compte à la fois certaines valeurs par défaut et fournir un moyen de comparer chaque entrée pour une approche générique que cela résout.
Utilisation: (donnant la valeur "seconde")
var defaultItemValue = { id: -1, name: "Undefined" };
var containers: Container[] = [{ id: 1, name: "First" }, { id: 2, name: "Second" }];
GetContainer(2).name;
La mise en oeuvre:
class Container {
id: number;
name: string;
}
public GetContainer(containerId: number): Container {
var comparator = (item: Container): boolean => {
return item.id == containerId;
};
return this.Get<Container>(this.containers, comparator, this.defaultItemValue);
}
private Get<T>(array: T[], comparator: (item: T) => boolean, defaultValue: T): T {
var found: T = null;
array.some(function(element, index) {
if (comparator(element)) {
found = element;
return true;
}
});
if (!found) {
found = defaultValue;
}
return found;
}
foundElement = myArray[myArray.findIndex(element => //condition here)];