/Javascript
Node.js

Map, filter, reduce

Ces trois fonctions sont utiles pour parcourir une liste (ou un tableau) et effectuer une sorte de transformation ou de calcul. Cela produira alors une nouvelle liste ou le résultat du calcul effectué sur la liste précédente.

Les types

Avant de plonger dans map, filter et reduce, configurons la liste.

const enum House {
  Gryffindor = "Gryffindor",
  Hufflepuff = "Hufflepuff",
  Ravenclaw = "Ravenclaw",
  Slytherin = "Slytherin"
}

type Wizard = {
  name: string;
  house: House;
  points: number;
};

types.ts

Chaque objet de l’assistant a un nom, une maison et le nombre de points qu’il a gagnés pour sa maison. Déclarons un groupe de magiciens et mettons-les dans une liste.

const HarryPotter: Wizard = {
  name: "Harry Potter",
  house: House.Gryffindor,
  points: 40
};

const HermioneGranger: Wizard = {
  name: "Hermione Granger",
  house: House.Gryffindor,
  points: 140
};

const DracoMalfoy: Wizard = {
  name: "Draco Malfoy",
  house: House.Slytherin,
  points: -20
};

const TaylorSwift: Wizard = {
  name: "Taylor Swift",
  house: House.Slytherin,
  points: 100
};

const LinManuelMiranda: Wizard = {
  name: "Lin Manuel Miranda",
  house: House.Slytherin,
  points: 5000
};

const CedricDiggory: Wizard = {
  name: "Cedric Diggory",
  house: House.Hufflepuff,
  points: 12
};

const SallyPerks: Wizard = {
  name: "Sally Perks",
  house: House.Hufflepuff,
  points: 15
};

const LunaLovegood: Wizard = {
  name: "Luna Lovegood",
  house: House.Ravenclaw,
  points: 100
};

const ChoChang: Wizard = {
  name: "Cho Chang",
  house: House.Ravenclaw,
  points: 100
};

const wizards: Wizard[] = [
  HarryPotter,
  HermioneGranger,
  DracoMalfoy,
  LinManuelMiranda,
  TaylorSwift,
  CedricDiggory,
  SallyPerks,
  LunaLovegood,
  ChoChang
];

wizards.ts

Map

Maintenant que nous avons la base, allons-y. La première fonction est la plus simple, map. Map itère (ou boucle) sur une liste, applique une fonction à chaque élément de cette liste, puis renvoie une nouvelle liste d’éléments transformés. Regardons un exemple.

const wizardNames = wizards.map(wizard => wizard.name);

wizard-names.ts

Cette fonction parcourt la liste des assistants, obtient leur nom et le place dans un nouveau tableau. Le résultat de ceci ressemble à ceci.

[
  "Harry Potter"undefined
  "Hermione Granger"undefined
  "Draco Malfoy"undefined
  "Lin Manuel Miranda"undefined
  "Taylor Swift"undefined
  "Cedric Diggory"undefined
  "Sally Perks"undefined
  "Luna Lovegood"undefined
  "Cho Chang"
];

Dans cet exemple, nous utilisions une fonction lambda (ou fonction anonyme), mais nous pouvons également utiliser une fonction nommée.

function wizardToString({ name, house, points }: Wizard) {
  return `${name}, ${house}, ${points}`;
}
const wizardStrings = wizards.map(wizardToString);

wizardToString.ts

Dans cet exemple, nous avons une fonction appelée wizardToString que nous transmettons directement au map. Il retournera alors une nouvelle liste qui ressemble à ceci.

[
  "Harry Potterundefined Gryffindorundefined 40"undefined
  "Hermione Grangerundefined Gryffindorundefined 140"undefined
  "Draco Malfoyundefined Slytherinundefined -20"undefined
  "Lin Manuel Mirandaundefined Slytherinundefined 5000"undefined
  "Taylor Swiftundefined Slytherinundefined 100"undefined
  "Cedric Diggoryundefined Hufflepuffundefined 12"undefined
  "Sally Perksundefined Hufflepuffundefined 15"undefined
  "Luna Lovegoodundefined Ravenclawundefined 100"undefined
  "Cho Changundefined Ravenclawundefined 100"
];

Filter

Le filter se comporte comme un map dans la mesure où il itère sur la liste, mais au lieu de transformer chaque élément, il transforme la liste entière. Le filter prend une fonction qui renvoie true ou false ou un prédicat. Il renvoie ensuite une nouvelle liste avec des éléments où le prédicat renvoie true. Regardons un exemple.

const slytherins = wizards.filter(wizard => wizard.house === House.Slytherin);

slytherins.ts

Dans cet exemple, nous filtrons par-dessus la liste et n’incluons que les sorciers qui se trouvent dans la maison Serpentard. Le résultat serait ceci.

[
  { name: "Draco Malfoy"undefined house: "Slytherin"undefined points: -20 }undefined
  { name: "Lin Manuel Miranda"undefined house: "Slytherin"undefined points: 5000 }undefined
  { name: "Taylor Swift"undefined house: "Slytherin"undefined points: 100 }
];

En passant, Taylor et Lin sont deux des Serpentards les plus acclamés de notre époque.

Comme avec map, nous n’avons pas besoin d’utiliser un lambda , nous pouvons également utiliser une fonction prédéfinie.

function isWinner({ points }: Wizard) {
  return points > 0;
}
function isLoser(wizard: Wizard) {
  return !isWinner(wizard);
}
const winners = slytherins.filter(wizard => wizard.points > 0);
const losers = slytherins.filter(wizard => wizard.points <= 0);

winners-losers.ts

Dans cet exemple, nous faisons deux listes, la liste des Serpentards ayant gagné des points (gagnants) et la liste des Serpentards ayant perdu des points (perdants). Nous pouvons voir ces résultats ci-dessous.

const winnersResult = [
  { name: "Lin Manuel Miranda"undefined house: "Slytherin"undefined points: 5000 }undefined
  { name: "Taylor Swift"undefined house: "Slytherin"undefined points: 100 }
];
const losersResult = [
  { name: "Draco Malfoy"undefined house: "Slytherin"undefined points: -20 }
];

Reduce

Nous arrivons maintenant à la fonction la plus intéressante, reduce. Reduce itère sur une liste et produit une valeur unique. Regardons un exemple.

Supposons que nous voulions obtenir le nombre total de points pour tous les assistants. Nous pouvons utiliser réduire pour faire cela.

const totalPoints = wizards.reduce(
  (accumulator, { points }) => accumulator + points,
  0
);

Que se passe t-il ici? Bien réduire est une fonction qui prend deux arguments, une fonction et une valeur initiale pour l’accumulateur. L’accumulateur est le nom de la chose réduire les rendements. Dans ce cas, nous commençons le compte de points à 0.

Maintenant, la fonction prend l’état actuel de l’accumulateur et de l’élément dans la liste qu’il est supposé traiter. Pour le premier assistant, il passera 0 pour l’accumulateur. Cette fonction retourne ensuite accumulator + points. Cela finira par résumer tous les points. Si vous êtes curieux, le résultat est 5487.

Maintenant, l’accumulateur peut être n’importe quoi, on peut même utiliser réduire pour produire un objet. Regardons un exemple où nous additionnons les points pour chaque maison.

const pointsPerHouse = wizards.reduce((acc, { house, points }) => {
  if (!acc[house]) {
    acc[house] = 0;
  }
  acc[house] += points;
  return acc;
}, {});

points-per-house.ts

Dans ce cas, nous initialisons notre accumulateur ou acc avec {}. Ensuite, pour chaque assistant, nous appelons une fonction qui ajoute le nombre de points qu’il a gagnés pour sa maison. Si vous êtes curieux, ce résultat ressemble à ceci.

{
  Gryffindor: 180undefined
  Slytherin: 5080undefined
  Hufflepuff: 27undefined
  Ravenclaw: 200
};

Regardons un autre exemple, disons que nous voulons le meilleur assistant pour chaque maison. Nous pouvons modifier notre fonction précédente pour utiliser le meilleur assistant pour chaque maison.

const bestPerHouse = wizards.reduce((acc, wizard) => {
  const { house, points } = wizard;
  if (!acc[house]) {
    acc[house] = wizard;
  }

  if (acc[house].points < points) {
    acc[house] = wizard;
  }

  return acc;
}, {});

Si vous êtes curieux, le résultat est le suivant.

{
  Gryffindor: { name: "Hermione Granger"undefined house: "Gryffindor"undefined points: 140 }undefined
  Slytherin: { name: "Lin Manuel Miranda"undefined house: "Slytherin"undefined points: 5000 }undefined
  Hufflepuff: { name: "Sally Perks"undefined house: "Hufflepuff"undefined points: 15 }undefined
  Ravenclaw: { name: "Luna Lovegood"undefined house: "Ravenclaw"undefined points: 100 }
};

Juste un peu plus de plaisir maintenant, nous pouvons utiliser Object.values pour transformer cet map.

const bestNamesPerHouse = Object.values(bestPerHouse).map(wizardToString);
[
  "Hermione Granger, Gryffindor, 140",
  "Lin Manuel Miranda, Slytherin, 5000",
  "Sally Perks, Hufflepuff, 15",
  "Luna Lovegood, Ravenclaw, 100"
];

best-names-per-house.ts

Maintenant, nous avons de beaux noms pour la meilleure personne dans chaque maison.

ludo

Développeur senior. Fullstack + DevOps