Les boucles foreach dans différents langages de programmation

Introduction

Comme beaucoup de développeurs, j’ai l’habitude de jongler entre différents langages de programmation selon les projets et les besoins. Et il y a cette petite chose qui me frustre régulièrement : je ne me souviens jamais de la syntaxe exacte des boucles foreach dans chaque langage !

Un jour c’est du Python, le lendemain du JavaScript, la semaine suivante je me retrouve sur du C# ou du Rust… Et à chaque fois, c’est la même rengaine : « Comment je fais déjà pour parcourir cette collection sans me prendre la tête ? » Faut-il utiliser « for », « foreach », « for in », « for of » ? Où vont les parenthèses, les accolades, les deux-points ?

J’ai donc décidé de créer ce pense-bête comparatif, autant pour mon usage personnel que pour tous ceux qui, comme moi, passent leur temps à chercher « how to foreach in [langage] » sur Google. Voici un guide simple et direct de cette foutue syntaxe de foreach dans les langages les plus courants.

Python

En Python, la boucle for est naturellement une boucle « foreach »:

python

<em># Parcourir une liste</em>
fruits = ["pomme", "banane", "orange"]
for fruit in fruits:
    print(fruit)

<em># Parcourir un dictionnaire</em>
ages = {"Alice": 25, "Bob": 30, "Charlie": 35}
for nom, age in ages.items():
    print(f"{nom} a {age} ans")

<em># Parcourir avec énumération (obtenir l'indice)</em>
for index, fruit in enumerate(fruits):
    print(f"{index}: {fruit}")

JavaScript

JavaScript propose plusieurs façons de parcourir des collections:

// Parcourir un tableau avec for...of (ES6+)
const fruits = ["pomme", "banane", "orange"];
for (const fruit of fruits) {
    console.log(fruit);
}

// Parcourir un objet avec for...in (pour les propriétés énumérables)
const personne = {nom: "Alice", age: 30, ville: "Paris"};
for (const propriete in personne) {
    console.log(`${propriete}: ${personne[propriete]}`);
}

// Méthode forEach sur les tableaux
fruits.forEach((fruit, index) => {
    console.log(`${index}: ${fruit}`);
});

Java

Java utilise le mot-clé for avec une syntaxe spéciale pour les boucles foreach:

String[] fruits = {"pomme", "banane", "orange"};
for (String fruit : fruits) {
    System.out.println(fruit);
}
// Parcourir une collection (ArrayList)
ArrayList<String> fruitsListe = new ArrayList<>(Arrays.asList("pomme", "banane", "orange"));
for (String fruit : fruitsListe) {
    System.out.println(fruit);
}
// Parcourir une Map
Map<String, Integer> ages = new HashMap<>();
ages.put("Alice", 25);
ages.put("Bob", 30);
ages.put("Charlie", 35);
for (Map.Entry<String, Integer> entry : ages.entrySet()) {
    System.out.println(entry.getKey() + " a " + entry.getValue() + " ans");
}

C#

C# utilise le mot-clé foreach:

// Parcourir un tableau
string[] fruits = {"pomme", "banane", "orange"};
foreach (string fruit in fruits)
{
    Console.WriteLine(fruit);
}

// Parcourir une liste
List<string> fruitsListe = new List<string> {"pomme", "banane", "orange"};
foreach (string fruit in fruitsListe)
{
    Console.WriteLine(fruit);
}

// Parcourir un dictionnaire
Dictionary<string, int> ages = new Dictionary<string, int>
{
    {"Alice", 25},
    {"Bob", 30},
    {"Charlie", 35}
};

foreach (KeyValuePair<string, int> kvp in ages)
{
    Console.WriteLine($"{kvp.Key} a {kvp.Value} ans");
}

C++

C++ propose plusieurs approches pour les boucles foreach:

#include <iostream>
#include <vector>
#include <map>

int main() {
    // Parcourir un tableau avec range-based for loop (C++11)
    std::string fruits[] = {"pomme", "banane", "orange"};
    for (const auto& fruit : fruits) {
        std::cout << fruit << std::endl;
    }
    
    // Parcourir un vecteur
    std::vector<std::string> fruitsVec = {"pomme", "banane", "orange"};
    for (const auto& fruit : fruitsVec) {
        std::cout << fruit << std::endl;
    }
    
    // Parcourir une map
    std::map<std::string, int> ages = {
        {"Alice", 25},
        {"Bob", 30},
        {"Charlie", 35}
    };
    
    for (const auto& [nom, age] : ages) {  // C++17 structured binding
        std::cout << nom << " a " << age << " ans" << std::endl;
    }
    
    return 0;
}

Rust

Rust utilise des itérateurs et le mot-clé for:

fn main() {
    // Parcourir un vecteur
    let fruits = vec!["pomme", "banane", "orange"];
    for fruit in &fruits {
        println!("{}", fruit);
    }
    
    // Parcourir avec énumération
    for (index, fruit) in fruits.iter().enumerate() {
        println!("{}: {}", index, fruit);
    }
    
    // Parcourir une HashMap
    use std::collections::HashMap;
    let mut ages = HashMap::new();
    ages.insert("Alice", 25);
    ages.insert("Bob", 30);
    ages.insert("Charlie", 35);
    
    for (nom, age) in &ages {
        println!("{} a {} ans", nom, age);
    }
}

PHP

PHP propose plusieurs syntaxes pour les boucles foreach:

<?php
// Parcourir un tableau
$fruits = ["pomme", "banane", "orange"];
foreach ($fruits as $fruit) {
    echo $fruit . "\n";
}

// Parcourir avec l'indice
foreach ($fruits as $index => $fruit) {
    echo $index . ": " . $fruit . "\n";
}

// Parcourir un tableau associatif
$ages = ["Alice" => 25, "Bob" => 30, "Charlie" => 35];
foreach ($ages as $nom => $age) {
    echo $nom . " a " . $age . " ans\n";
}
?>

Ruby

Ruby propose plusieurs méthodes pour parcourir des collections:

# Parcourir un tableau
fruits = ["pomme", "banane", "orange"]
fruits.each do |fruit|
  puts fruit
end

# Parcourir avec l'indice
fruits.each_with_index do |fruit, index|
  puts "#{index}: #{fruit}"
end

# Parcourir un hash
ages = {"Alice" => 25, "Bob" => 30, "Charlie" => 35}
ages.each do |nom, age|
  puts "#{nom} a #{age} ans"
end

Lua

Lua utilise les fonctions pairs et ipairs:

-- Parcourir une table séquentielle (array-like)
fruits = {"pomme", "banane", "orange"}
for index, fruit in ipairs(fruits) do
    print(index .. ": " .. fruit)
end

-- Parcourir une table associative
ages = {Alice = 25, Bob = 30, Charlie = 35}
for nom, age in pairs(ages) do
    print(nom .. " a " .. age .. " ans")
end

Go

Go utilise le mot-clé range:

package main

import "fmt"

func main() {
    // Parcourir un slice
    fruits := []string{"pomme", "banane", "orange"}
    for index, fruit := range fruits {
        fmt.Printf("%d: %s\n", index, fruit)
    }
    
    // Parcourir uniquement les valeurs
    for _, fruit := range fruits {
        fmt.Println(fruit)
    }
    
    // Parcourir une map
    ages := map[string]int{
        "Alice":   25,
        "Bob":     30,
        "Charlie": 35,
    }
    
    for nom, age := range ages {
        fmt.Printf("%s a %d ans\n", nom, age)
    }
}

Swift

Swift utilise le mot-clé for...in:

// Parcourir un tableau
let fruits = ["pomme", "banane", "orange"]
for fruit in fruits {
    print(fruit)
}

// Parcourir avec indices
for (index, fruit) in fruits.enumerated() {
    print("\(index): \(fruit)")
}

// Parcourir un dictionnaire
let ages = ["Alice": 25, "Bob": 30, "Charlie": 35]
for (nom, age) in ages {
    print("\(nom) a \(age) ans")
}

Kotlin

Kotlin utilise également le mot-clé for:

// Parcourir une liste
val fruits = listOf("pomme", "banane", "orange")
for (fruit in fruits) {
    println(fruit)
}

// Parcourir avec indices
for ((index, fruit) in fruits.withIndex()) {
    println("$index: $fruit")
}

// Parcourir une map
val ages = mapOf("Alice" to 25, "Bob" to 30, "Charlie" to 35)
for ((nom, age) in ages) {
    println("$nom a $age ans")
}

TypeScript

TypeScript étend les capacités de JavaScript:

// Parcourir un tableau
const fruits: string[] = ["pomme", "banane", "orange"];
for (const fruit of fruits) {
    console.log(fruit);
}

// Parcourir un objet
const personne: {[key: string]: any} = {nom: "Alice", age: 30, ville: "Paris"};
for (const propriete in personne) {
    console.log(`${propriete}: ${personne[propriete]}`);
}

// Utilisation de forEach avec typage
fruits.forEach((fruit: string, index: number) => {
    console.log(`${index}: ${fruit}`);
});

Remarques générales

  1. Performance: Les boucles foreach sont généralement optimisées pour la lisibilité plutôt que pour la performance. Dans certains cas (comme avec les collections très grandes), des méthodes alternatives peuvent être plus efficaces.
  2. Modification pendant l’itération: La plupart des langages déconseillent ou interdisent la modification de la collection pendant son parcours avec foreach.
  3. Utilisation avec les itérateurs: Les boucles foreach masquent souvent l’utilisation d’itérateurs, ce qui facilite l’écriture de code mais peut cacher certains comportements spécifiques.
  4. Compatibilité: Toutes les collections ne sont pas nécessairement compatibles avec les boucles foreach dans tous les langages. Vérifiez la documentation de votre langage pour les détails spécifiques.

Conclusion

J’espère que cette petite compilation vous sera aussi utile qu’à moi. Personnellement, je garde cette page en favori et je la consulte à chaque fois que mon cerveau fait le choix conscient d’oublier comment fonctionne une boucle foreach en [insérez n’importe quel langage ici].

Si vous avez d’autres syntaxes à ajouter ou des astuces pour mieux mémoriser ces structures, n’hésitez pas à les partager en commentaire !

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *