0Pricing
C# Academy · Lekcja

IComparer do niestandardowego sortowania

Zapewniaj alternatywne porządki za pomocą porównywaczy.

IComparer do niestandardowego sortowania to bezpłatna lekcja C# Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej C# Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs C# Academy zawiera 4 lekcji w sumie.

Sortowanie na różne sposoby

Typ ma tylko jeden porządek naturalny, określony przez IComparable<T>. Aby sortować te same dane na inne sposoby, należy przekazać w miejscu wywołania obiekt IComparer<T> albo delegat Comparison<T>.

Implementacja IComparer<T>

IComparer<T> to osobny obiekt z metodą Compare(x, y). Obowiązuje w nim ten sam kontrakt wartości ujemnej, zera i wartości dodatniej co w przypadku CompareTo.

using System;
using System.Collections.Generic;

public class Person
{
    public string Name;
    public int Age;
    public Person(string name, int age) { Name = name; Age = age; }
    public override string ToString() => Name + "(" + Age + ")";
}

public class ByName : IComparer<Person>
{
    public int Compare(Person x, Person y)
        => string.Compare(x.Name, y.Name, StringComparison.Ordinal);
}

public class Program
{
    public static void Main()
    {
        var people = new List<Person> { new Person("Zoe", 1), new Person("Ann", 2) };
        people.Sort(new ByName());
        Console.WriteLine(string.Join(", ", people));
    }
}

Wiele komparatorów dla jednego typu

Można zdefiniować kilka komparatorów i wybrać jeden dla każdego sortowania. W tym przykładzie te same osoby można na żądanie sortować według nazwiska albo wieku.

using System;
using System.Collections.Generic;

public class Person
{
    public string Name;
    public int Age;
    public Person(string name, int age) { Name = name; Age = age; }
    public override string ToString() => Name + "(" + Age + ")";
}

public class ByAge : IComparer<Person>
{
    public int Compare(Person x, Person y) => x.Age.CompareTo(y.Age);
}

public class Program
{
    public static void Main()
    {
        var people = new List<Person> { new Person("Ann", 40), new Person("Bo", 20) };
        people.Sort(new ByAge());
        Console.WriteLine(string.Join(", ", people));
    }
}

Delegat Comparison<T>

W przypadku jednorazowego sortowania delegat Comparison<T>, często w postaci lambdy, jest zwięźlejszy niż cała klasa. List.Sort przyjmuje go bezpośrednio.

using System;
using System.Collections.Generic;

public class Program
{
    public static void Main()
    {
        var words = new List<string> { "banana", "fig", "apple" };
        // Sort by length using a Comparison<string> lambda
        words.Sort((a, b) => a.Length.CompareTo(b.Length));
        Console.WriteLine(string.Join(", ", words));
    }
}

Sortowanie malejące z komparatorem

Aby odwrócić porządek, należy zamienić argumenty miejscami wewnątrz metody Compare. Dzięki temu można uzyskać sortowanie malejące bez modyfikowania samego typu.

using System;
using System.Collections.Generic;

public class DescendingInt : IComparer<int>
{
    public int Compare(int x, int y) => y.CompareTo(x);
}

public class Program
{
    public static void Main()
    {
        var nums = new List<int> { 3, 1, 4, 1, 5 };
        nums.Sort(new DescendingInt());
        Console.WriteLine(string.Join(", ", nums));
    }
}

Komparatory w OrderBy

Metoda LINQ OrderBy przyjmuje obiekt IComparer<TKey> jako drugi argument, co pozwala dostosować sposób porównywania wybranych kluczy.

using System;
using System.Collections.Generic;
using System.Linq;

public class CaseInsensitive : IComparer<string>
{
    public int Compare(string x, string y)
        => string.Compare(x, y, StringComparison.OrdinalIgnoreCase);
}

public class Program
{
    public static void Main()
    {
        var names = new[] { "bob", "Alice", "carol" };
        foreach (var n in names.OrderBy(x => x, new CaseInsensitive()))
            Console.WriteLine(n);
    }
}

Porównywanie według wielu kluczy

Komparator może sortować według kilku kluczy w kolejności ich ważności. Należy obliczyć pierwszy klucz, a w przypadku remisu przejść do następnego.

using System;
using System.Collections.Generic;

public class Employee
{
    public string Dept;
    public int Salary;
    public Employee(string dept, int salary) { Dept = dept; Salary = salary; }
    public override string ToString() => Dept + ":" + Salary;
}

public class ByDeptThenSalary : IComparer<Employee>
{
    public int Compare(Employee x, Employee y)
    {
        int byDept = string.Compare(x.Dept, y.Dept, StringComparison.Ordinal);
        return byDept != 0 ? byDept : x.Salary.CompareTo(y.Salary);
    }
}

public class Program
{
    public static void Main()
    {
        var staff = new List<Employee>
        {
            new Employee("IT", 50), new Employee("HR", 40), new Employee("IT", 30)
        };
        staff.Sort(new ByDeptThenSalary());
        Console.WriteLine(string.Join(", ", staff));
    }
}

Skrót z Comparer.Create

Comparer<T>.Create tworzy obiekt IComparer<T> na podstawie lambdy, łącząc zwięzłość delegata z interfejsami API wymagającymi komparatora.

using System;
using System.Collections.Generic;

public class Program
{
    public static void Main()
    {
        var byLengthDesc = Comparer<string>.Create((a, b) => b.Length.CompareTo(a.Length));
        var words = new List<string> { "hi", "hello", "hey" };
        words.Sort(byLengthDesc);
        Console.WriteLine(string.Join(", ", words));
    }
}

Ponowne używanie komparatorów w kolekcjach

Pojedyncza instancja komparatora może służyć do sortowania, wyszukiwania i obsługi uporządkowanych zbiorów. Zdefiniowanie jej raz zapewnia spójność reguł porządkowania we wszystkich miejscach, w których jest używana.

using System;
using System.Collections.Generic;

public class Program
{
    public static void Main()
    {
        IComparer<int> desc = Comparer<int>.Create((a, b) => b.CompareTo(a));
        var set = new SortedSet<int>(desc) { 1, 5, 3 };
        Console.WriteLine(string.Join(", ", set));
    }
}

Wybór między IComparable a IComparer

IComparable<T> należy stosować do jednego porządku naturalnego zaszytego w typie. IComparer<T> lub Comparison<T> należy stosować do wielu alternatywnych porządków zależnych od kontekstu, wybieranych w miejscu wywołania.

using System;
using System.Collections.Generic;

public class Program
{
    public static void Main()
    {
        var nums = new List<int> { 5, 2, 8, 1 };
        nums.Sort(); // natural ascending (int is IComparable)
        Console.WriteLine(string.Join(", ", nums));
        nums.Sort((a, b) => b - a); // custom descending via delegate
        Console.WriteLine(string.Join(", ", nums));
    }
}

Spróbuj samodzielnie

Posortuj jedną listę na trzy różne sposoby za pomocą komparatorów i lambdy, nie modyfikując przy tym typu elementów.

using System;
using System.Collections.Generic;

public class Program
{
    public static void Main()
    {
        var words = new List<string> { "pear", "fig", "apple", "kiwi" };

        words.Sort(); // natural alphabetical
        Console.WriteLine(string.Join(", ", words));

        words.Sort((a, b) => a.Length.CompareTo(b.Length)); // by length
        Console.WriteLine(string.Join(", ", words));

        words.Sort(Comparer<string>.Create((a, b) => b.CompareTo(a))); // reverse alphabetical
        Console.WriteLine(string.Join(", ", words));
    }
}

Szybkie sprawdzenie

Wybierz właściwą abstrakcję porządkowania.

Podsumowanie

Własne sortowanie korzysta z komparatorów przekazywanych w miejscu wywołania.

  • IComparer<T> implementuje metodę Compare(x, y) z kontraktem wartości ujemnej, zera i wartości dodatniej.
  • Delegaty Comparison<T> i lambdy sprawdzają się przy jednorazowym sortowaniu.
  • Comparer<T>.Create łączy lambdy z interfejsem.
  • IComparable służy do porządku naturalnego, a komparatory do porządków alternatywnych.

Często zadawane pytania

Czy lekcja „IComparer do niestandardowego sortowania” jest bezpłatna?

Tak — pełny tekst „IComparer do niestandardowego sortowania” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu C# Academy, przejdź na CoddyKit PRO. Kurs C# Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „IComparer do niestandardowego sortowania”?

Zapewniaj alternatywne porządki za pomocą porównywaczy. Ćwiczysz C# Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć C# Academy?

Nie wymagamy żadnego doświadczenia. C# Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.

Ile czasu zajmuje lekcja „IComparer do niestandardowego sortowania”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji C# Academy?

Tak. Każda lekcja C# Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Implementowanie IEquatable
  2. Przesłanianie GetHashCode
  3. Implementowanie IComparable
  4. IComparer do niestandardowego sortowania
← Powrót do C# Academy