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

Autor: Paweł Sołtysiak

Opublikowano: 2012-03-14

Kolekcje obiektów możemy sortować za pomocą operatora zapytań LINQ o nazwie OrderBy. Tworzy on nową kolekcję, w której elementy są posortowane według wybranego przez programistę klucza. Opcjonalnie możemy zdefiniować własną klasę porównującą, dzięki czemu możemy posortować kolekcję według własnego algorytmu. To świetny sposób na uniknięcie pisania wielolinijkowego kodu. Taki kod jest łatwiejszy w późniejszej modyfikacji oraz czytelniejszy dla innych programistów.

Przed wykonaniem zadań powinieneś wiedzieć:

  • jak utworzyć nowy projekt konsolowy w Visual Studio (od wersji 2008),
  • jak posługiwać się tablicami oraz kolekcjami,
  • jak utworzyć nową klasę w języku C#.

Po wykonaniu zadań nauczysz się:

  • jak sortować kolekcję przy użyciu operatora OrderBy o wskazanym kluczu,
  • jak zdefiniować dodatkowy klucz sortowania,
  • jak sortować kolekcję przy użyciu klasy porównującej.

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 OrderBy, a także przetestowanie działania operatora ThenBy.

Operator OrderBy – sortowanie alfabetyczne

Użycie operatora OrderBy w celu posortowania słów alfabetycznie.

  1. Otwórz plik o nazwie Program.cs
  2. Wewnątrz funkcji Main wpisz:
var words = new string[] { "sok", "mleko", "piwo", "herbata", "kawa", "woda" };
var sortedWords = from word in words
                  orderby word
                  select word;
foreach (var word in sortedWords)
{
    Console.WriteLine(word);
}
  1. Uruchom program za pomocą Debug -> Start Without Debugging (Ctrl+F4)
  2. Powinien uruchomić się program wyświetlający słowa z tablicy w kolejności alfabetycznej. Tak, jak zostało to zaprezentowane na Rys. 1.

Rys. 1. Słowa z tablicy w kolejności alfabetycznej.

Informacja
sortedWords jest nową kolekcją, w której elementy zostały posortowane według kolejności alfabetycznej. Po słowie kluczowym orderby, następuje wskazanie klucza, według którego następuje sortowanie. Wybrany klucz musi implementować interfejs o nazwie IComparable.

Operator OrderBy Descending – odwrócenie sortowania

Przy korzystaniu z operatora OrderBy, czasem możemy potrzebować odwrócenia kolejności sortowania.

  1. Zamień kod z poprzedniego zadania następującym kodem:
var numbers = new int[] { 3, 7, 2, 1, 9, 5, 0, 4, 6 };
var sortedNumbers = from number in numbers
                    orderby number descending
                    select number;
foreach (var number in sortedNumbers)
{
    Console.WriteLine(number);
}
  1. Uruchom program za pomocą Debug ‑> Start Without Debugging (Ctrl+F4)
  2. Powinien uruchomić się program, wyświetlający liczby z tablicy w kolejności malejącej. Tak, jak przedstawiono to na Rys. 2.

Rys. 2. Program wyświetla liczby w kolejności malejącej.

Informacja
Operator OrderBy sortuje domyślnie elementy w kolekcji, w sposób rosnący. Dodanie słowa kluczowego descending umożliwia odwrócenie kolejności sortowania.

Operator ThenBy

Gdy sortujemy słowa, np. według ich długości, może się tak zdarzyć, że dwa słowa (lub więcej) będą miały taką samą długość. Ich kolejność zależy od kolejności występowania w pierwotnej kolekcji. Możemy wpłynąć na tą kolejność, ustawiając dodatkowy warunek. Kolejny warunek ustawia się przy pomocy ThenBy.

  1. Zamień kod z poprzedniego zadania następującym kodem:
var words = new string[] { "sok", "mleko", "woda", "piwo", "herbata", "kawa" };
var sortedWords = from word in words
                  orderby word.Length, word
                  select word;
foreach (var word in sortedWords)
{
    Console.WriteLine(word);
}
  1. Uruchom program za pomocą Debug -> Start Without Debugging (Ctrl+F4).
  2. Powinien uruchomić się program wyświetlający słowa, w kolejności od najkrótszego do najdłuższego. Słowa o takiej samej długości zostały posortowane alfabetycznie. Tak, jak zostało to zilustrowane na Rys. 3.

Rys. 3. Słowa w kolejności od najdłuższego do najkrótszego. Słowa o takiej samej długości są sortowane według alfabetu.

Informacja
W tym przykładzie, operator ThenBy jest wykorzystany w sposób niejawny. Przecinek, występujący po word.Length, zamieniany jest przez kompilator na operator ThenBy.

Operator OrderBy z klasą porównującą

W momencie, kiedy chcemy zmienić sposób porównywania obiektów przy użyciu OrderBy, musimy utworzyć osobną klasę, w której będzie znajdował się kod porównujący dwa obiekty z kolekcji.

  1. Usuń kod z poprzedniego ćwiczenia.
  2. Powyżej klasy Program (class Program) wpisz:
public class OrdinalComparer: IComparer<string>
{
    public int Compare(string x, string y)
    {
        return string.Compare(x, y, StringComparison.Ordinal);
    }
}
  1. Wewnątrz metody Main wpisz:
var words = new string[] { "sok",  "herbata", "HERBATNIKI", "woda", "kawa", "KAWIARNIA" };
var sortedWords = words.OrderBy(a => a, new OrdinalComparer());
foreach (var word in sortedWords)
{
    Console.WriteLine(word);
}
  1. Uruchom program za pomocą Debug -> Start Without Debugging (Ctrl+F4).
  2. Powinien uruchomić się program wyświetlający na początku posortowane słowa, napisane dużymi literami, a następnie słowa napisane małymi literami. Tak, jak przedstawia to Rys. 4.

Rys. 4. Na początku słowa napisane dużymi literami, a następnie słowa napisane małymi literami.

Informacja

W kroku 2. utworzyłeś klasę implementującą interfejs IComparer<string>. Ten interfejs wymaga napisania jednej metody o nazwie Compare. W naszym przypadku, w tej metodzie zwracana jest wartość pochodząca od innej statycznej metody, porównującej ciągi znaków.

PodanieStringComparison.Ordinal sprawia, że znaki w ciągach porównywane są na podstawie pierwszeństwa wystąpienia tego znaku w tabeli ASCII, a nie na podstawie kolejności jego wystąpienia w alfabecie.

Dowiedz się więcej na temat interfejsu IComparer z encyklopedii, a także o innych wartościach wyliczeniowych StringComparison z encyklopedii MSDN.

Podsumowanie

W tym artykule nauczyłeś się, jak wykorzystać do sortowania obiektów w kolekcji operator OrderBy w LINQ, a także, jak odwrócić kolejność sortowania. Ponadto, dowiedziałeś się o operatorze ThenBy, pozwalającym na dodanie kolejnej reguły sortowania. Na końcu, poznałeś możliwości wykorzystania klasy porównującej.

W kolejnym artykule nauczymy się, jak tworzyć nowe obiekty za pomocą LINQ.