Полное руководство. С# 4.0 - Шилдт Герберт
Шрифт:
Интервал:
Закладка:
Содержимое массива нередко приходится сортировать. Для этой цели в классеArray предусмотрен обширный ряд сортирующих методов. Так, с помощью разных вариантов метода Sort() можно отсортировать массив полностью или в заданных пределах либо отсортировать два массива, содержащих соответствующие пары"ключ-значение". После сортировки в массиве можно осуществить эффективный поиск, используя разные варианты метода BinarySearch(). В качестве примера нижеприведена программа, в которой демонстрируется применение методов Sort()и BinarySearch() для сортировки и поиска в массиве значений типа int.// Отсортировать массив и найти в нем значение.using System;class SortDemo { static void Main() { int[] nums = { 5, 4, 6, 3, 14, 9, 8, 17, 1, 24, -1, 0 }; // Отобразить исходный порядок следования. Console.Write("Исходный порядок следования: "); foreach(int i in nums) Console.Write(i + " "); Console.WriteLine(); // Отсортировать массив. Array.Sort(nums); // Отобразить порядок следования после сортировки. Console.Write("Порядок следования после сортировки: "); foreach(int i in nums) Console.Write(i + " "); Console.WriteLine(); // Найти значение 14. int idx = Array.BinarySearch(nums, 14); Console.WriteLine("Индекс элемента массива со значением 14: " + idx); }}
Вот к какому результату приводит выполнение этой программы.Исходный порядок следования: 5 4 6 3 14 9 8 17 1 24 -1 0Порядок следования после сортировки: -1 0 1 3 4 5 6 8 9 14 17 24Индекс элемента массива со значением 14: 9
В приведенном выше примере массив состоит из элементов типа int, который относится к категории типов значений. Все методы, определенные в классе Array, автоматически доступны для обработки массивов всех встроенных в C# типов значений.Но в отношении массивов ссылок на объекты это правило может и не соблюдаться.Так, для сортировки массива ссылок на объекты в классе типа этих объектов долженбыть реализован интерфейс IComparable или IComparable. Если же ни один изэтих интерфейсов не реализован в данном классе, то во время выполнения программыможет возникнуть исключительная ситуация в связи с попыткой отсортировать подобный массив или осуществить в нем поиск. Правда, реализовать оба интерфейса,IComparable и IComparable<T>, совсем нетрудно.
В интерфейсе IComparable определяется один метод.int CompareTo(object obj)
В этом методе значение вызывающего объекта сравнивается со значением объекта,определяемого параметром obj. Если значение вызывающего объекта больше, чему объекта obj, то возвращается положительное значение; если оба значения равны —нулевое значение, а если значение вызывающего объекта меньше, чем у объекта obj, —отрицательное значение.
Интерфейс IComparable является обобщенным вариантом интерфейсаIComparable. Поэтому в нем определен следующий обобщенный вариант методаCompareTo().int CompareTo(Т other)
Обобщенный вариант метода CompareTo() действует аналогично необобщенномуего варианту. В нем значение вызывающего объекта также сравнивается со значениемобъекта, определяемого параметром other. Если значение вызывающего объекта больше, чем у объекта other, то возвращается положительное значение; если оба значенияравны — нулевое значение, а если значение вызывающего объекта меньше, чем у объекта other, — отрицательное значение. Преимущество интерфейса IComparable заключается в том, что он обеспечивает типовую безопасность, поскольку в этом случаетип обрабатываемых данных указывается явным образом, а следовательно, никакогоприведения типа object сравниваемого объекта к нужному типу не требуется. В качестве примера ниже приведена программа, в которой демонстрируются сортировкаи поиск в массиве объектов определяемого пользователем класса.// Отсортировать массив объектов и осуществить в нем поиск.using System;class MyClass : IComparable<MyClass> { public int i; public MyClass(int x) { i = x; } // Реализовать интерфейс IComparable<MyClass>. public int CompareTo(MyClass v) { return i - v.i; } public bool Equals(MyClass v) { return i == v.i; }}class SortDemo { static void Main() { MyClass[] nums = new MyClass[5]; nums[0] = new MyClass(5); nums[1] = new MyClass(2); nums[2] = new MyClass (3); nums[3] = new MyClass (4); nums[4] = new MyClass (1); // Отобразить исходный порядок следования. Console.Write("Исходный порядок следования: "); foreach(MyClass о in nums) Console.Write(о.i + " "); Console.WriteLine(); // Отсортировать массив. Array.Sort(nums); // Отобразить порядок следования после сортировки. Console.Write("Порядок следования после сортировки: "); foreach(MyClass о in nums) Console.Write(о.i + " "); Console.WriteLine(); // Найти объект MyClass (2). MyClass x = new MyClass(2); int idx = Array.BinarySearch(nums, x); Console.WriteLine("Индекс элемента массива с объектом MyClass(2): " + idx); }}
При выполнении этой программы получается следующий результат.Исходный порядок следования: 5 2 3 4 1Порядок следования после сортировки: 1 2 3 4 5Индекс элемента массива с объектом MyClass(2): 1
При сортировке или поиске в массиве строк может возникнуть потребность явноуказать способ сравнения символьных строк. Так, если массив будет сортироваться сиспользованием одних настроек культурной среды, а поиск в нем — с помощью других настроек, то во избежание ошибок, скорее всего, придется явно указать способсравнения. Аналогичная ситуация возникает и в том случае, если требуется отсортировать массив символьных строк при настройках культурной среды, отличающихся оттекущих. Для выхода из подобных ситуаций можно передать экземпляр объекта типаStringComparer параметру типа IComparer, который поддерживается в целом рядеперегружаемых вариантов методов Sort() и BinarySearch().
ПРИМЕЧАНИЕБолее подробно особенности сравнения строк рассматриваются в главе 22.
Класс StringComparer объявляется в пространстве имен System и реализует,среди прочего, интерфейсы IComparer и IComparer<T>. Поэтому экземпляр объекта типа StringComparer может быть передан в качестве аргумента параметру типаIComparer. Кроме того, в классе StringComparer определен ряд доступных толькодля чтения свойств, возвращающих экземпляр объекта типа StringComparer и поддерживающих различные способы сравнения символьных строк. Все эти свойства перечислены ниже.СвойствоСпособ сравненияpublic static StringComparer CurrentCulture {get; }С учетом регистра и культурной средыpublic static StringComparer CurrentCultureIgnoreCase {get; }Без учета регистра, но с учетом культурной средыpublic static StringComparer InvariantCulture {get; }С учетом регистра и безотносительно к культурной средеpublic static StringComparer InvariantCultureIgnoreCase {get; }Без учета регистра и безотносительно к культурной средеpublic static StringComparer Ordinal {get; }Порядковое сравнение с учетом регистраpublic static StringComparer OrdinalIgnoreCase {get; }Порядковое сравнение без учета регистра
Передавая явным образом экземпляр объекта типа StringComparer, можно совершенно однозначно определить порядок сортировки или поиска в массиве. Например, в приведенном фрагменте кода сортировка и поиск в массиве символьных строкосуществляется с помощью свойства StringComparer.Ordinal.string[] strs = { "xyz", "one" , "beta", "Alpha" };// ...Array.Sort(strs, StringComparer.Ordinal);int idx = Array.BinarySearch(strs, "beta", StringComparer.Ordinal);Обращение содержимого массива
Иногда оказывается полезно обратить содержимое массива и, в частности, отсортировать по убывающей массив, отсортированный по нарастающей. Для такого обращения массива достаточно вызвать метод Reverse(). С его помощью можно обратитьсодержимое массива полностью иди частично. Этот процесс демонстрируется в приведенной ниже программе.// Обратить содержимое массива.using System;class ReverseDemo { static void Main() { int[] nums = { 1, 2, 3, 4, 5 }; // Отобразить исходный порядок следования. Console.Write("Исходный порядок следования: "); foreach(int i in nums) Console.Write(i + " "); Console.WriteLine(); // Обратить весь массив. Array.Reverse(nums); // Отобразить обратный порядок следования. Console.Write("Обратный порядок следования: "); foreach(int i in nums) Console.Write(i + " "); Console.WriteLine(); // Обратить часть массива. Array.Reverse(nums, 1, 3); // Отобразить обратный порядок следования. Console.Write("Частично обращенный порядок следования: "); foreach(int i in nums) Console.Write(i + " "); Console.WriteLine(); }}