Dictionnaire et fonctions en TypeScript

Manipulation de données textuelles en TypeScript : dictionnaire, expression régulière, etc.

→ Challenge Correction: Affaire BL4CKWELL – Mademoiselle Mirage

Pour ce 3ème challenge de Top Code 2025, il fallait découper des chaines de caractères pour pouvoir extraire certaines informations clés, et comparer ces informations clés à un référentiel.

On va donc procéder en 3 grandes phases :

Création d’un dictionnaire en TypeScript

On commence par transformer le tableau travels en un objet qu’on appelle dictionnaire.

L’objectif est de passer de :

["2025-09:Bruxelles", "2025-02:Austin", "2025-08:Bangkok"]

// à

{
  "2025-09": "Bruxelles",
  "2025-02": "Austin",
  "2025-08": "Bangkok",
  ...
}

Voici comment faire :

const travelMap: Record<string, string> = travels.reduce((acc, travel) => {
  const [month, city] = travel.split(':');
  acc[month] = city;
  return acc;
}, {});

Un peu d’explications :

  • travelMap sera typé Record<string, string>, c’est un type TypeScript qui précise que c’est un objet dont les clés sont des chaînes (string) et les valeurs aussi.
  • La méthode reduce permet de transformer un tableau en une seule valeur. Ici, cette valeur est un objet.
  • Chaque élément de travels est une chaine (comme "2025-09:Bruxelles") qu’on découpe avec la .split(':') pour alors récupérer un tableau (comme ["2025-09", "Bruxelles"]).
  • On assigne ces deux éléments de tableau à deux variables avec la destructuration
  • On stocke l’information dans l’objet acc : la clé est le mois ("2025-09"), la valeur est la ville ("Bruxelles").

Ce format va être très pratique pour retrouver rapidement une ville selon le mois donné, sans devoir parcourir le tableau à chaque fois.

Construction de 2 fonctions en TypeScript

La première fonction consiste à extraire les informations d’une photo pour pouvoir les manipuler plus efficacement. Comme les photos ont toutes une structure similaire, on peut utiliser une expression régulière (regex). La syntaxe des expressions régulières est assez complexe à maitriser mais plusieurs outils en ligne sont disponibles pour nous aider dans leur conception. A l’usage, c’est plus efficace qu’un enchainement de découpage avec split ou autre.

Voici l’expression régulière utilisée :

/(\d{4}-\d{2})-\d{2}:file_(.+)_(\d+)\.JPG/

Un peu d’explications :

  • (\d{4}-\d{2}) permet de récupérer la date partielle au format YYYY-MM
  • -\d{2} correspond au jour DD, non récupéré (pas de parenthèses)
  • :file_ est une partie fixe de la chaine de caractères
  • (.+) permet de récupérer la ville
  • _(\d+) permet de récupérer le nom de la photo
  • \.JPG est l’extension, échappée, fixe également dans la chaine de caractères

Et intégrée dans une fonction :

function extractPhotoData(photo: string): { date: string; city: string; number: string } | null {
  const match = photo.match(/(\d{4}-\d{2})-\d{2}:file_(.+)_(\d+)\.JPG/);
  if (!match) return null;
  const [, date, city, number] = match;
  return { date, city, number };
}

Un peu d’explications :

  • On crée une fonction qui prend en paramètre une chaine de caractères et qui retournera un objet ou null. Cet objet retourné contiendra 3 propriétés, 3 chaines de caractères : date, city et number
  • On applique l’expression régulière sur photo
  • Si la structure n’est pas respectée, on retourne null, c’est une sécurité pour ne pas créer une erreur sur la ligne suivante si jamais photo ne contenait pas ce qui est attendu. Dans le cadre du challenge, ce n’est pas possible.
  • On utilise à nouveau de la destructuration pour récupérer les 3 valeurs dans 3 variables
  • On retourne ces 3 variables dans un même objet unique

La deuxième fonction sert à savoir si une photo est fake ou non

function isTruePhoto(photo: string, travelMap: Record<string, string>): boolean {
  const data = extractPhotoData(photo);
  if (!data) return false;
  return travelMap[data.date] == data.city;
}

Un peu d’explications :

  • Cette fonction prend en paramètre une chaine de caractères photo (donnée de l’énoncé) et un objet travelMap qui correspond au dictionnaire créé lors de la première étape.
  • Cette fonction retourne un booléen, true ou false.
  • On extraie les données de la photo dans data
    • Si ça ne fonctionne pas, on retourne false
  • Et on vérifie la correspondance de la date et de la ville dans travelMap
    • Si ça correspond, on retourne true pour indiquer que la photo est réelle
    • A l’inverse, on retourne false pour indiquer qu’elle est fake

Programme principal

function findFakePhotos(photos: string[], travelMap: Record<string, string>): string {
  let result = "";
  for (const photo of photos) {
    const data = extractPhotoData(photo);
    if (data && !isTruePhoto(photo, travelMap)) {
      result += data.number;
    }
  }
  return result;
}

// Exécution
const result = findFakePhotos(photos, travelMap);

console.log(result);

Un peu d’explications :

  • Cette fonction prend en paramètre un tableau de chaines de caractères, que sont les données de l’énoncé et, encore une fois, notre dictionnaire travelMap
  • Cette fonction retourne une chaine de caractères, qui correspond à la réponse au challenge
  • On crée une chaine de caractères result vide
  • On parcourt chaque photo de photos
  • On extraie les données puis si la photo est fake, on concatène son numéro dans result
  • Une fois toutes les photos parcourues, on retourne result
  • La fonction est alors exécutée puis son résultat affiché

Conclusion

Ce challenge met en avant un aspect important de la programmation : savoir découper les informations, puis séquencer intelligemment les opérations.

Dans un flot de données brutes comme des noms de fichiers ou des logs, tout commence par l’extraction rigoureuse des éléments utiles. Ici, l’utilisation d’une expression régulière précise, intégrée dans une fonction dédiée (extractPhotoData), permet de poser une base claire et isolée du reste de la logique.

Ensuite vient la phase d’analyse : on encapsule le raisonnement métier dans une fonction simple (isTruePhoto), ce qui rend le code plus lisible, plus testable, et surtout réutilisable. Enfin, la résolution s’appuie sur un enchaînement logique et lisible, sans jamais mélanger les responsabilités : extraire, évaluer, accumuler.


Qui a codé ce superbe contenu ?

Keep learning

Other content to discover