LINQ i kolekcje obiektów - Wyszukiwanie obiektów  Udostępnij na: Facebook

Autor: Paweł Sołtysiak

Opublikowano: 2012-03-13

Wyszukiwanie pewnej grupy obiektów wewnątrz kolekcji to zadanie, które często musimy wykonywać. Do jego przeprowadzenia możemy użyć operatora zapytań LINQ o nazwie Where, który pozwala na utworzenie nowej kolekcji z już istniejącej. Dzięki zastosowaniu operatora Where, nie musimy wykorzystywać pętli, np. foreach. Ten kod jest bardziej zwięzły, a także łatwiejszy do utrzymania w przyszłości.

Przed wykonaniem zadań powinieneś wiedzieć:

  • jak utworzyć nowy projekt konsolowy w Visual Studio (od wersji 2008),
  • jak posługiwać się tablicami oraz kolekcjami obiektów w C#,
  • jak działa pętla foreach.

Po wykonaniu zadań nauczysz się:

  • jak wyszukiwać obiekty w pamięci za pomocą operatora Where.

Implementacja

W Visual Studio (od wersji 2008) utwórz nowy projekt konsolowy dla języka C#.

Twoim zadaniem będzie sprawdzenie, jak działa operator Where.

Operator Where

  1. Otwórz plik o nazwie Program.cs.
  2. Wewnątrz funkcji Main wpisz:
int[] liczby = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };

var niskieLiczby =
    from n in liczby
    where n < 5
    select n;

Console.WriteLine("Liczby < 5:");
foreach (var x in niskieLiczby)
{
    Console.WriteLine(x);
}
  1. Uruchom program za pomocą Debug->Start Without Debugging (Ctrl+F5)
  2. Powinien uruchomić się program wyświetlający liczby, znajdujące się w tablicy, ale tylko te, które są mniejsze niż 5. Tak, jak zaprezentowano to na Rys. 1.

Rys. 1. Program wyświetla liczby z tablicy, które są mniejsze od 5.

Informacja
W kodzie zadeklarowaliśmy tablicę o nazwie liczby, która służy do przechowywania liczb całkowitych. Następnie, wyrażenie LINQ przechodzi po każdym elemencie w tablicy i wybiera tylko ten element, który spełnia warunek n < 5. Z tych, wybranych elementów tworzona jest nowa kolekcja o nazwie niskieLiczby.

Inny zapis operatora Where

Operator Where możemy zapisać również w inny sposób.

  1. Zamień kod z poprzedniego zadania następującym kodem:
int[] liczby = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };

var wysokieLiczby = liczby.Where( liczba => liczba > 5);    

Console.WriteLine("Liczby > 5:");
foreach (var x in wysokieLiczby)
{
    Console.WriteLine(x);
}
  1. Uruchom program za pomocą Debug->Start Without Debugging (Ctrl+F5).
  2. Powinien uruchomić się program wyświetlający liczby, znajdujące się w tablicy, ale tylko te, które są większe niż 5. Tak, jak przedstawiono to na Rys. 2.

Rys. 2. Program wyświetla liczby z tablicy, które są większe od 5.

Informacja

Wewnątrz operatora Where korzystamy z wyrażenia lambda, które przyjmuje jeden parametr – pojedynczy obiekt kolekcji. Dysponując pojedynczym obiektem, sprawdzamy warunek, od którego zależy, czy przekazany obiekt zostanie zamieszczony w nowej kolekcji, która zostanie zwrócona przez operator Where.

Więcej informacji o wyrażeniu lambda przeczytasz w encyklopedii pod hasłem: Lambda Expressions (C# Programming Guide).

Indeksowanie

Przy korzystaniu z operatora Where otrzymujemy indeks elementu w kolekcji, którymoże zostać użyty w wyrażeniu boolowskim.

  1. Zamień kod z poprzedniego zadania, następującym kodem:
string[] cyfry = { "zero", "jeden", "dwa", "trzy", "cztery", "pięć", "sześć", "siedem", "osiem", "dziewięć" }; 

var krotkieCyfry = cyfry.Where((cyfra, indeks) => cyfra.Length < indeks); 

Console.WriteLine("Krótkie cyfry:"); 
foreach (var c in krotkieCyfry) 
{ 
    Console.WriteLine("Słowo {0} jest krótsze niż jego wartość.", c); 
}
  1. Uruchom program za pomocą Debug->Start Without Debugging (Ctrl+F5).
  2. Powinien uruchomić się program wyświetlający słowa, które są krótsze niż wartość wyrażona słowem. Tak, jak ilustruje to Rys. 3.

Rys. 3. Program wyświetla nazwy cyfr, które są krótsze niż ich wartość.

Informacja
W porównaniu z poprzednim ćwiczeniem, w parametrach wyrażenia lambda, pojawił się nowy parametr. Przekazuje on informacje o indeksie aktualnego obiektu. Indeks jest porównywany z długością słowa i na tej podstawie podjęta zostaje decyzja o włączeniu słowa do nowej kolekcji.

Wykorzystanie funkcji wewnątrz warunku

Operator Where nie musi sam obliczać warunku, np. przy użyciu operatorów numerycznych. Może skorzystać z każdej funkcji, która zwraca typ bool.

  1. Usuń funkcję Main i w jej miejsce umieść następujący kod:
static bool WiecejNizSiedem(int x)
{
    Console.WriteLine("{0} - więcej niż 7?", x);
    return x > 7;
}
static bool MniejNizTrzy(int x)
{
    Console.WriteLine("{0} - mniej niż 3?", x);
    return x < 3;
}
static void Main(string[] args)
{
    var liczby = new int[] { 5, 4, 1, 3, 8, 9, 7, 2, 0 };
    var wynik1 = from x in liczby
                 where MniejNizTrzy(x)
                 select x;
    var wynik2 = from x in liczby
                 where WiecejNizSiedem(x)
                 select x;
    foreach (var liczba in wynik1) Console.WriteLine(liczba);
    foreach (var liczba in wynik2) Console.WriteLine(liczba);
}
  1. Uruchom program za pomocą Debug->Start Without Debugging (Ctrl+F5).
  2. Powinien uruchomić się program wyświetlający liczby z tabeli oraz komunikaty o aktualnie sprawdzanej wartości. Tak, jak zostało to zaprezentowane na Rys. 4.

Rys. 4. Program wyświetla informacje o elemencie, który jest aktualnie sprawdzany.

Informacja

Dzięki zastosowaniu funkcji wewnątrz operatora Where, możemy wykonać serie instrukcji sprawdzających.

Należy również zauważyć, że wynik zapytania LINQ nie jest budowany w momencie jego deklaracji, ale w momencie, w którym po raz pierwszy odwołujemy się do niego.

Podsumowanie

W tym artykule nauczyłeś się, jak wyszukiwać obiekty za pomocą LINQ i operatora Where. Poznałeś dwa sposoby zapisu: długi i krótki. Dodatkowo, dowiedziałeś się o możliwości wykorzystania indeksu obiektu w kolekcji. Na końcu, sprawdziłeś możliwości wykorzystywania osobnych funkcji, które pozwalają na bardziej rozbudowane testowanie.

W kolejnym artykule nauczymy się sortować wyszukane obiekty.