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.IComparablesł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
- Implementowanie IEquatable
- Przesłanianie GetHashCode
- Implementowanie IComparable
- IComparer do niestandardowego sortowania