Pętla for

Pętla for wykonuje się określoną liczbę razy.
Konstrukcja pętli for:
for ( inicjalizacja zmiennej; warunek logiczny; wyrażenie aktualizujące zmienną){
// instrukcje
}
Zmienna jest inicjalizowana na początku pętli. Przy jej pierwszym wykonaniu sprawdzany jest warunek, a po każdym wykonaniu bloku kodu zmienna jest poddawana aktualizacji. Następnie po raz kolejny sprawdzany jest warunek , jeżeli jest błędny, pętla zakańcza działanie , w przeciwnym wypadku pętla wykonuje się dalej. Aktualizować zmienną możemy poprzez wyrażenie, które zmniejszy lub zwiększy daną zmienną lub poprzez zastosowanie inkrementacji bądź dekrementacji.
Zobaczmy prosty przykład, wypiszmy 10 razy na ekranie napis podany przez użytkownika:

  class Program {
        static void Main() {
            Console.WriteLine("Podaj napis");
            string Napis = Console.ReadLine();
            Console.WriteLine("Wyświetlamy 10 razy :");
            for (int i = 0; i < 10;i++ ) {
                Console.WriteLine(Napis);
            }
            Console.ReadLine();
        }
    }

Rezultat działania aplikacji:

Pętla for, foreach

Rys. Wyświetlenie łańcucha znaków podanego przez użytkownika 10 razy

Aplikacja wypisała nam na ekranie 10 razy napis, który podał jej użytkownik. Dopiszmy do niej pewną zmianę. Chcę aby przy każdym napisie wypisana została liczba porządkowa.
Poprawmy kod:
Aby to zrobić musimy najpierw zmienić pętlę for, a dokładnie wartość inicjacji zmiennej o nazwie i, powinna się zaczynać od 1 a nie od 0. Następnie musimy zmienić warunek w pętli. W tej chwili sprawdza on czy wartość zmiennej o nazwie “i” jest mniejsza od 10. Możemy zatem stworzyć warunek aby wartość zmiennej i była mniejsza lub równa 10. Kolejnym krokiem jest zmiana komunikatu, który wyświetla się na ekranie.
Kod:

class Program {
        static void Main() {
            Console.WriteLine("Podaj napis");
            string Napis = Console.ReadLine();
            Console.WriteLine("Wyświetlamy 10 razy :");
            for (int i = 1; i <= 10;i++ ) {
                Console.WriteLine("{0}.{1}", i, Napis);
            }
            Console.ReadLine();
        }
    }

Rezultat działania aplikacji:

Pętla for, foreach

Rys. Wypisanie 10 razy na ekranie łańcucha znaków podanego przez użytkownika

Aplikacja działa poprawnie. Oczywiście liczba w warunku pętli nie musi być typu int. Zobaczmy przykład:

   class Program {
        static void Main() {  
            for (double i = 0.1; i <= 2;i=i+0.1 ) {
                Console.WriteLine("{0}", i);
            }
            Console.ReadLine();
        }
    }

Oto rezultat działania aplikacji:

Pętla for, foreach

Rys. Wyświetlenie wartości liczy zwiększanej o 0.1 dziesięć razy w pętli for. Wartość początkowa 0.1

W pętli for możemy zastosować słowo kluczowe break. Jego zadaniem jest zakończenie działania pętli. Zobaczmy prosty przykład:

   class Program {
        static void Main() {  

            for (int i = 1; i <= 20;i++ ) {
                if (i == 10)
                    break;             
  
                Console.WriteLine("{0}", i);
            }
            Console.ReadLine();
        }
    }

Rezultat działania aplikacji:

Pętla for, foreach

Rys. Wyświetlenie wartości

Pętla powinna się wykonać 20 razy, ale poprzez zastosowanie słowa kluczowego break przerwane zostało działanie po 10 przebiegach.
Słowa kluczowego break używamy najczęściej gdy chcemy ograniczyć zbędne wykonania pętli.

W pętli for możemy użyć słowa kluczowego continue, jego zadaniem jest wymuszenie wykonania następnego przebiegu pętli z pominięciem kodu, który znajduje się po tym słowie kluczowym. Zobaczmy przykład:

class Program {
        static void Main() {  
            for (int i = 1; i <= 10;i++ ) {               
                if (i == 4)
                    continue; 
                Console.WriteLine("Przebieg pętli: {0}", i);
            }
            Console.ReadLine();
        }
    } 

Rezultat działania aplikacji:

Pętla for, foreach

Rys. Wyświetlenie przebiegów pętli

Przy czwartym przebiegu pętli warunek w instrukcji if zostaje spełniony przez co wykonuje się polecenie continue i wymuszony zostaje następny przebieg pętli, powoduje to, że kod znajdujący się za tym poleceniem czyli wyświetlenie przebiegu pętli na ekranie nie zostaje wykonany.

Napiszmy następującą aplikację :
Niech program wypisze na ekranie 10 wierszy, a w każdym z nich o jeden znak „*” więcej.
Kod:

class Program {
        static void Main() {
            for (int i = 0; i< 10; i++) {
                for (int j = 0; j <= i; j++) {
                    Console.Write("*");
                }
                Console.WriteLine();
            }

            Console.ReadLine();
        }
    }

Rezultat działania aplikacji:

Pętla for, foreach

Rys. Wyświetlenie znaków ”*”

Aby ten przykład wykonać w pętli for użyłem kolejnej pętli for. Czyli bez problemu możemy tworzyć pętlę w pętli.

Ciekawostka:

Tak jak w przypadku pętli while, istnieje możliwość wystąpienia nieskończonej ilości wywołań pętli możemy to zrobić np w następujący sposób:
Nie podając nic w nawiasach:

  for (;;) {
            Console.WriteLine("....");
        }

lub omijając warunek logiczny podczas deklaracji pętli:

 for (int i=0; ; i++) {
            Console.WriteLine("...."+i);
        }

bądź podając zły warunek logiczny

 for (int i=0; i&amp;amp;amp;gt;-200; i++) {
            Console.WriteLine("...."+i);
        }

 

Pętla foreach

Pętla ta ma za zadanie powtarzanie kodu bloku, który się w niej znajduje dla każdego elementu w kolekcji. O kolekcjach napiszę w innym artykule.
Konstrukcja pętli:

foreach(typ zmienna in kolekcja){
//instrukcje
}

W pętli foreach musimy zadeklarować typ jaki się znajduje w kolekcji, następnie podać nazwę zmiennej. Ona będzie przechowywać podczas przebiegu pętli element kolekcji. Następnie podajemy przez jaką kolekcję „przechodzić” ma pętla.

W przykładzie skorzystam ze zmiennej typu string, jest to kolekcja znaków char. Aplikacja będzie miała za zadanie wypisanie na ekranie każdego znaku w osobnej linii.

Kod programu:

  class Program {
        static void Main() {
            string napis = "Napis testowy";

            foreach (char znak in napis) {
                Console.WriteLine(znak);
            }            
            Console.ReadLine();
        }
    }

Rezultat działania aplikacji:

Pętla for, foreach

Rys. Wypisanie każdego znaku z zmiennej typu char w osobnej linii.

Oczywiście pętle foreach możemy zastąpić pętlą for bez najmniejszego problemu. Przeróbmy powyższy przykład:

class Program {
        static void Main() {
            string napis = "Napis testowy";

            for (int i = 0; i < napis.Length; i++) {
                Console.WriteLine(napis[i]);
            }
            Console.ReadLine();
        }
    }

Rezultat działania aplikacji jest identyczny.
Czytelniejszym sposobem jest zastosowanie pętli foreach zamiast for.

UWAGA:
Należy pamiętać, że podczas wykorzystania pętli foreach elementy kolekcji są tylko do odczytu i nie jesteśmy w stanie ich zmienić. Zobaczmy przykład :

 class Program {
        static void Main() {
            string[] tablica = new string[3] {
                "Adam","Aga","Edek"
            };
            foreach (string imie in tablica) {
                if (imie == "Aga") {
                    imie = "Agnieszka";
                }
                Console.WriteLine(imie);
            }
            Console.ReadLine();
        }
    }

Kompilator zwróci następujący błąd:

Pętla for, foreach

Rys. Błąd zgłoszony przez kompilator.

Gdy spróbujemy zmodyfikować kolekcję poprzez dodanie lub usunięcie elementu otrzymamy wyjątek.

Pętla foreach  a kolekcja obiektów typu referencyjnego

Kolekcja obiektów typu referencyjnego, przechowuje tylko referencję (adres w pamięci) a nie wartości tych obiektów. Przez co, możemy za pomocą pętli foreach zmieniać składowe obiektów oraz wykonywać ich metody. Oczywiście nie jest możliwa zmiana kolekcji poprzez dodanie elementu czy jego usunięcie podczas iteracji pętli. Nie możemy, także zmienić referencji elementu.

Zobaczmy przykład:

using System;
using System.Collections.Generic;

public class Pracownik {
    public string Imie { get; set; }
    public string Nazwisko { set; get; }
    public string ImieINazwisko() {
        return $"{Imie} {Nazwisko}";
    }
}
class Program {
    static void Main() {
        List<Pracownik> pracownicy = new List<Pracownik>() {
                new Pracownik {Imie ="Adam",Nazwisko="Kan" },
                new Pracownik {Imie ="Zbigniew",Nazwisko="Zakanski" },
                new Pracownik {Imie ="Agnieszka",Nazwisko="Mag" },
            };
        Console.WriteLine("Pracownicy przed zmianą:");

        foreach (Pracownik pracownik in pracownicy)
            Console.WriteLine(pracownik.ImieINazwisko());

        foreach (Pracownik pracownik in pracownicy)
            pracownik.Nazwisko = "Kowalski";

        Console.WriteLine("Pracownicy po zmianie nazwiska na Kowalski");
        foreach (Pracownik pracownik in pracownicy)
            Console.WriteLine(pracownik.ImieINazwisko()); ;

        Console.ReadLine();
    }
}

Rezultat działania aplikacji:

petle

Rys. Rezultat działania aplikacji

W tej chwili ten kod może być niezrozumiały w całości. Polecam powrócić do tego wpisu po zapoznaniu się z klasami. Jak widzimy możemy zmienić wartość składowej obiektu.

Ciekawostka:

W przypadku pętli foreach nie jest mi znany sposób sprawienia aby wykonywała się ona w nieskończoność.

Podsumowanie:
Każda pętla ma swoje naturalne zastosowanie:
– pętlę while używamy gdy chcemy aby blok kodu zawarty w pętli wykonywał się dopóki warunek w niej zawarty będzie prawdziwy.
– pętlę „do while” używamy gdy chcemy aby blok kodu zawarty w pętli wykonał się przynajmniej raz.
– pętlę for używamy gdy chcemy aby blok kodu zawarty w pętli wykonał się określoną liczbę razy.
– pętlę foreach stosujemy gdy chcemy wykonać blok kodu w niej zawarty dla każdego elementu z kolekcji.