J’ai récemment mis en place un tutoriel pour certains étudiants et je suis tombé sur un problème que je suis sûr que nous avons tous rencontré à un moment ou à un autre. J’avais ce tableau d’objets et dans chaque objet j’avais un id. Je voulais un moyen rapide et efficace de regarder tous les ids et de trouver l’id maximum.
Dans cet article, je vais vous guider à travers 4 solutions différentes.
- Array.forEach
- Array.map
- Array.reduce
- Math.max
Mise en place de votre projet
J’utilise Node pour exécuter cet exemple mais vous pouvez tout aussi bien utiliser JavaScript et déposer ceci dans une page web. La première chose que je vais faire est de requérir le module assert de Node qui nous donne la possibilité de fournir un ensemble simple de tests d’assertion.
const assert = require("assert");
Après, vous allez créer un tableau de caractères. J’ai récemment lu le livre Bad Blood, j’ai donc décidé d’utiliser certains des personnages de ce livre. Note secondaire : si vous n’avez pas encore lu ce livre, je vous le recommande vivement. Chaque personnage dans le tableau va être un objet qui contient un id, un prénom et un nom de famille.
const characters = ;
Dans chaque solution possible, vous voulez écrire une logique qui retournera le plus grand id dans le tableau.
Array.forEach
Votre première pensée pourrait être d’itérer sur le tableau en utilisant un type de boucle et pourquoi pas, c’est ce qu’on vous a appris à faire depuis que vous avez commencé à écrire du code. Vous pouvez commencer par déclarer un max de zéro, itérer sur chaque caractère et si son id est plus grand que le max, mettre à jour le max.
let max = 0;characters.forEach(character => { if (character.id > max) { max = character.id; }});assert(max === 444);
Mon objectif principal à chaque fois que j’écris du code est de faire fonctionner quelque chose d’abord et de l’améliorer ensuite. Si vous deviez exécuter ce code, il fonctionne certainement, mais il ne me semble pas correct. Que se passe-t-il si vous avez mille ou un million d’objets dans le tableau ? Chaque fois que je commence à itérer sur un tableau en utilisant un certain type de boucle pour effectuer quelque calcul, c’est un énorme drapeau rouge pour moi.
Array.map
Chaque fois que ce drapeau rouge d’itération sur un tableau apparaît, je me demande immédiatement si c’est quelque chose que map/filtre/réduit peut résoudre. Donc si vous alliez adopter cette approche ici, vous pouvez commencer avec la méthode map. La méthode map()
crée un nouveau tableau avec les résultats de l’appel d’une fonction fournie sur chaque élément du tableau appelant. Vous utiliserez la méthode map pour créer un nouveau tableau contenant uniquement les identifiants, de sorte que vous ne travaillerez plus avec des objets. À ce stade, vous pouvez simplement utiliser la méthode de tri normale sur le tableau, saisir le dernier élément de la liste et c’est votre id max.
const ids = characters.map(user => user.id);const sorted = ids.sort((a, b) => a - b);assert(sorted === 444);
Si vous vouliez être vraiment fantaisiste, vous pouvez faire tout cela en une seule déclaration.
assert( characters.map(user => user.id).sort((a, b) => a - b) === 444);
Array.reduce
La méthode reduce()
exécute une fonction réductrice (que vous fournissez) sur chaque membre du tableau résultant en une seule valeur de sortie. Ici, vous allez appeler reduce sur le tableau de caractères. Vous allez définir un accumulateur qui accumulera la valeur de retour de la callback. Chaque fois que la fonction callback est appelée, elle renvoie une valeur et la stocke dans max. La méthode de callback regarde l’identifiant du caractère et s’il est supérieur à max, elle le renvoie, sinon elle renvoie max. Enfin, elle doit définir une valeur par défaut pour max et c’est ce que characters.id
fait.
const maxId = characters.reduce( (max, character) => (character.id > max ? character.id : max), characters.id);assert(maxId === 444);
Si vous remarquez, c’est une approche similaire à celle que nous utilisons avec la méthode forEach, en itérant sur chaque élément et en le comparant à max. La différence ici est que l’utilisation de reduce est beaucoup plus rapide. Vous pouvez également utiliser une combinaison de reduce et de la solution suivante Math.max()
si vous le souhaitez.
L’opérateur d’étalement
Bien que j’aime l’approche map et reduce beaucoup mieux que l’itération sur le tableau, cela ne me semble toujours pas génial. Si vous creusez dans Math.max, vous découvrirez qu’il peut prendre une liste de nombres ou un tableau de nombres.
Cela signifie que tout ce que vous avez à faire est d’obtenir un tableau d’id et vous pouvez le passer dans la fonction max()
. Si vous avez été attentif, vous avez déjà fait cela plus tôt en utilisant map. Cela signifie que vous pouvez utiliser la fonction map pour obtenir un tableau d’id et ensuite le passer dans la fonction max()
en utilisant l’opérateur spread.
assert(Math.max(...characters.map(user => user.id)) === 444);
La syntaxe d’étalement permet à un itérable tel qu’une expression de tableau ou une chaîne de caractères d’être développée à des endroits où zéro ou plusieurs arguments (pour les appels de fonction) ou éléments (pour les littéraux de tableau) sont attendus, ou une expression d’objet d’être développée dans les endroits où zéro ou plusieurs paires clé-valeur (pour les littéraux d’objet) sont attendus.
C’est pour moi la solution la plus propre et il se trouve que je l’aime beaucoup.
Résultats de performance
Je ne voulais pas transformer cela en un article sur la programmation fonctionnelle en JavaScript mais c’est là que nous avons atterri. J’ai fait un chronométrage de base de chacune des fonctions (en utilisant console.time()
&console.timeEnd()
) et j’ai trouvé les résultats suivants.
- Testiterate : 0,217ms
- Test de carte : 0,191ms
- test de réduction : 0,144ms
- test d’étalement : 0,148ms
Conclusion
Bien que l’utilisation de reduce nous ait donné un tout petit avantage de performance, je préfère utiliser Math.max et l’opérateur spread ici. Pour moi, cela semble juste plus propre et c’est quelque chose que j’aime écrire. Si vous aviez ce problème, quelle solution choisiriez-vous ? En ai-je oublié une ? J’espère que vous avez aimé marcher à travers la façon dont je résoudrais ce problème et jusqu’à la prochaine fois…
Happy CodingDan
.