Текст книги "C# 4.0: полное руководство"
Автор книги: Герберт Шилдт
Жанр:
Программирование
сообщить о нарушении
Текущая страница: 60 (всего у книги 83 страниц)
public static void Sort(Array keys, Array items, int index, int length) – Сортирует по нарастающей два одномерных массива в.заданных пределах, начиная с элемента, указываемого по индексу index, и включая число элементов, определяемых параметром length. Массив keys содержит ключи сортировки, а массив i terns — значения, связанные с этими ключами. Следовательно, оба массива должны содержать пары “ключ-значение". После сортировки элементы обоих массивов располагаются в заданных пределах по порядку возрастания ключей
public static void Sort
public static void Sort(Array keys, Array items, int index, int length, IComparer comparer) – Сортирует по нарастающей два одномерных массива в заданных пределах, начиная с элемента, указываемого по индексу index, и включая число элементов, определяемых параметром length, а также используя способ сравнения, задаваемый параметром comparer. Массив keys содержит ключи сортировки, а массив items — значения, связанные с этими ключами. Следовательно, эти два массива должны содержать пары “ключ-значение". После сортировки элементы обоих массивов располагаются в заданных пределах по порядку возрастания ключей
public static void Sort
public static bool TrueForAll
Сортировка и поиск в массивах
Содержимое массива нередко приходится сортировать. Для этой цели в классе 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
, совсем нетрудно.
В интерфейсе 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
public int i;
public MyClass(int x) {
i = x;
}
// Реализовать интерфейс IComparable
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<Т>
. Поэтому экземпляр объекта типа StringComparer
может быть передан в качестве аргумента параметру типа IComparer
. Кроме того, в классе StringComparer
определен ряд доступных только для чтения свойств, возвращающих экземпляр объекта типа StringComparer
и поддерживающих различные способы сравнения символьных строк. Все эти свойства перечислены ниже.
Свойство – Способ сравнения
public static StringComparer CurrentCulture {get; } – С учетом регистра и культурной среды
public static StringComparer CurrentCulturelgnoreCase {get; } – Без учета регистра, но с учетом культурной среды
public static StringComparer InvariantCulture {get; } – С учетом регистра и безотносительно к культурной среде
public static StringComparer InvariantCulturelgnoreCase {get; } – Без учета регистра и безотносительно к культурной среде
public static StringComparer Ordinal {get; } – Порядковое сравнение с учетом регистра
public static StringComparer OrdinallgnoreCase {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();
}
}
Эта программа дает следующий результат.
Исходный порядок следования: 1 2 3 4 5
Обратный порядок следования: 5 4 3 2 1
Частично обращенный порядок следования: 5 2 3 4 1
Копирование массива
Полное или частичное копирование одного массива в другой – это еще одна весьма распространенная операция с массивами. Для копирования содержимого массива служит метод Сору()
. В зависимости от его варианта копирование элементов исходного массива осуществляется в начало или в средину целевого массива. Применение метода Сору()
демонстрируется в приведенном ниже примере программы.
// Скопировать массив.
using System;
class CopyDemo {
static void Main() {
int[] source = { 1, 2, 3, 4, 5 };
int[] target = { 11, 12, 13, 14, 15 };
int[] source2 = { -1, -2, -3, -4, -5 };
// Отобразить исходный массив.
Console.Write("Исходный массив: ");
foreach (int i in source)
Console.Write(i + " ");
Console.WriteLine();
// Отобразить исходное содержимое целевого массива.
Console.Write("Исходное содержимое целевого массива: ");
foreach (int i in target)
Console.Write(i +" ");
Console.WriteLine();
// Скопировать весь массив.
Array.Copy(source, target, source.Length);
// Отобразить копию.
Console.Write("Целевой массив после копирования: ");
foreach (int i in target)
Console.Write(i + " ");
Console.WriteLine();
// Скопировать в средину целевого массива.
Array.Copy(source2, 2, target, 3, 2);
// Отобразить копию.
Console.Write("Целевой массив после частичного копирования: ");
foreach (int i in target)
Console.Write(i + " ");
Console.WriteLine();
}
}
Выполнение этой программы дает следующий результат.
Исходный массив: 1 2 3 4 5
Исходное содержимое целевого массива: 11 12 13 14 15
Целевой массив после копирования: 1 2 3 4 5
Целевой массив после частичного копирования: 1 2 3 -3 -4
Применение предиката
Предикат представляет собой делегат типа System.Predicate
, возвращающий логическое значение true
или false
в зависимости от некоторого условия. Он объявляется следующим образом.
public delegate bool Predicate
Объект, проверяемый по заданному условию, передается в качестве параметра obj
. Если объект obj
удовлетворяет заданному условию, то предикат должен возвратить логическое значение true
, в противном случае – логическое значение false
. Предикаты используются в ряде методов класса Array
, включая: Exists()
, Find()
, Findlndex()
и FindAll()
.
В приведенном ниже примере программы демонстрируется применение предиката с целью определить, содержится ли в целочисленном массиве отрицательное значение. Если такое значение обнаруживается, то данная программа извлекает первое отрицательное значение, найденное в массиве. Для этого в ней используются методы Exists()
и Find()
.
//Подемострировать применеие предикатного делегата
using System;
class PredDemo {
// Предикатный метод, возвращающий логическое значение true,
// если значение переменной v оказывается отрицательным,
static bool IsNeg(int v) {
if (v < 0) return true;
return false;
}
static void Main() {
int[] nums = { 1, 4, -1, 5, -9 };
Console.Write("Содержимое массива nums: ");
foreach (int i in nums)
Console.Write(i + " ");
Console.WriteLine();
// Сначала проверить, содержит ли массив nums отрицательное значение,
if (Array.Exists(nums, PredDemo.IsNeg)) {
Console.WriteLine(«Массив nums содержит отрицательное значение.»);
// Затем найти первое отрицательное значение" в массиве,
int x = Array.Find(nums, PredDemo.IsNeg);
Console.WriteLine("Первое отрицательное значение: " + x);
}
else
Console.WriteLine(«В массиве nums отсутствуют отрицательные значения.»);
}
}
Эта программа дает следующий результат.
Содержимое массива nums: 1 4 -1 5 -9
Массив nums содержит отрицательное значение.
Первое отрицательное значение: -1
В данном примере программы в качестве предиката методам Exists()
и Find()
передается метод IsNeg()
. Обратите внимание на следующее объявление метода IsNeg()
.
static bool IsNeg (int v) {
Методы Exists()
и Find()
автоматически и по порядку передают элементы массива переменной v. Следовательно, после каждого вызова метода IsNeg()
переменная v будет содержать следующий элемент массива.
Применение делегата Action
Делегат Action
применяется в методе Array.ForEach()
для выполнения заданного действия над каждым элементом массива. Существуют разные формы делегата Action
, отличающиеся числом параметров типа. Ниже приведена одна из таких форм.
public delegate void Action
В этой форме объект, над которым должно выполняться действие, передается в качестве параметра obj
. Когда же эта форма делегата Action
применяется в методе Array.ForEach()
, то каждый элемент массива передается по порядку объекту obj
.
Следовательно, используя делегат Action
и метод ForEach()
, можно в одном операторе выполнить заданную операцию над целым массивом.
В приведенном ниже примере программы демонстрируется применение делегата Action
и метода ForEach()
. Сначала в ней создается массив объектов класса MyClass
, а затем используется метод Show()
для отображения значений, извлекаемых из этого массива. Далее эти значения становятся отрицательными с помощью метода Neg()
. И наконец, метод Show()
используется еще раз для отображения отрицательных значений. Все эти операции выполняются посредством вызовов метода ForEach()
.
// Продемонстрировать применение делегата Action.
using System;
class MyClass {
public int i;
public MyClass(int x) {
i = x;
}
}
class ActionDemo {
// Метод делегата Action, отображающий значение, которое ему передается,
static void Show(MyClass о) {
Console.Write(о.i + " ");
}
// Еще один метод делегата Action, делающий
// отрицательным значение, которое ему передается.
static void Neg(MyClass o) {
o.i = -o.i;
}
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("Содержимое массива nums: ");
// Выполнить действие для отображения значений.
Array.ForEach(nums, ActionDemo.Show);
Console.WriteLine();
// Выполнить действие для отрицания значений.
Array.ForEach(nums, ActionDemo.Neg);
Console.Write("Содержимое массива nums после отрицания: ");
// Выполнить действие для повторного отображения значений.
Array.ForEach(nums, ActionDemo.Show);
}
}
Ниже приведен результат выполнения этой программы.
Содержимое массива nums: 5 2 3 4 1
Содержимое массива nums после отрицания: -5 -2 -3 -4 -1
В программировании нередко требуется преобразовать встроенный тип данных в массив байтов. Допустим, что на некоторое устройство требуется отправить целое значение, но сделать это нужно отдельными байтами, передаваемыми по очереди. Часто возникает и обратная ситуация, когда данные получаются из устройства в виде упорядоченной последовательности байтов, которые требуется преобразовать в один из встроенных типов. Для подобных преобразований в среде .NET предусмотрен отдельный класс BitConverter
.
Класс BitConverter
является статическим. Он содержит методы, приведенные в табл. 21.13. Кроме того, в нем определено следующее поле.
public static readonly bool IsLittleEndian
Это поле принимает логическое значение true
, если в текущей среде сначала сохраняется младший байт слова, а затем старший. Это так называемый формат с прямым порядком байтов. А если в текущей среде сначала сохраняется старший байт слова, а затем младший, то поле IsLittleEndian
принимает логическое значение false
. Это так называемый формат с обратным порядком байтов. В компьютерах с процессором Intel Pentium используется формат с прямым порядком байтов.
Таблица 21.13. Методы, определенные в классе BitConverter
Метод - Назначение
public static long DoubleToInt64Bits (double value) – Преобразует значение value в целочисленное значение типа long и возвращает результат
public static byte[] GetBytes (bool value) – Преобразует значение value в однобайтовый массив и возвращает результат
public static byte[] GetBytes (char value) – Преобразует значение value в двухбайтовый массив и возвращает результат
public static byte[] GetBytes (double value) – Преобразует значение value в восьмибайтовый массив и возвращает результат
public static byte[] GetBytes (float value) – Преобразует значение value в четырехбайтовый массив и возвращает результат
public static byte[] GetBytes (int value) – Преобразует значение value в четырехбайтовый массив и возвращает результат
public static byte[] GetBytes (long value) – Преобразует значение value в восьмибайтовый массив и возвращает результат
public static byte[] GetBytes (short value) – Преобразует значение value в двухбайтовый массив и возвращает результат
public static byte[] GetBytes (uint value) – Преобразует значение value в четырехбайтовый массив и возвращает результат
public static byte[] GetBytes (ulong value) – Преобразует значение value в восьмибайтовый массив и возвращает результат
public static byte[] GetBytes(ushortvalue) – Преобразует значение value в двухбайтовый массив и возвращает результат
public static double Int64BitsToDouble(long value) – Преобразует значение value в значение типа double и возвращает результат
public static bool ToBoolean(byte[]value, intstartlndex) – Преобразует байт из элемента массива, указываемого по индексу value [startlndex], в эквивалентное значение типа bool и возвращает результат. Ненулевое значение преобразуется в логическое значение true, а нулевое – в логическое значение false
public static char ToChar(byte[]value, int index) – Преобразует два байта, начиная с элемента массива value [ index], в эквивалентное значение типа char и возвращает результат
public static double – ToDouble(byte[]value, intstartlndex) – Преобразует восемь байтов, начиная с элемента массива value [startlndex], в эквивалентное значение типа double и возвращает результат
public static short Tolntl6(byte[]value, intstartlndex) – Преобразует два байта, начиная с элемента массива value [startlndex], в эквивалентное значение типа short и возвращает результат
public static int ToInt32(byte[]value, intstartlndex) – Преобразует четыре байта, начиная с элемента массива value [startlndex], в эквивалентное значение типа int и возвращает результат
public static long ToInt64(byte[]value, intstartlndex) – Преобразует восемь байтов, начиная с элемента массива value [startlndex], в эквивалентное значение типа long и возвращает результат
public static float ToSingle(byte[]value, intstartlndex) – Преобразует четыре байта, начиная с элемента массива value [startlndex], в эквивалентное значение типа float и возвращает результат
public static string ToString(byte[]value) – Преобразует байты из массива value в символьную строку. Строка содержит шестнадцатеричные значения, связанные с этими байтами и разделенные дефисами
public static string ToString(byte[]value, intstartlndex) – Преобразует байты из массива value в символьную строку, начиная с элемента value[startindex]. Строка содержит шестнадцатеричные значения, связанные с этими байтами и разделенные дефисами
public static string ToString(byte[]value, intstartlndex,int length) – Преобразует байты из массива value в символьную строку, начиная с элемента value [ startlndex] и включая число элементов, определяемых параметром length. Строка содержит шестнадцатеричные значения, связанные с этими байтами и разделенные дефисами
public static ushort ToUIntl6(byte[]value, intstartlndex) – Преобразует два байта, начиная с элемента массива value [startlndex], в эквивалентное значение типа ushort и возвращает результат
public static uint ToUInt32(byte[]value, intstartlndex) – Преобразует четыре байта, начиная с элемента массива value[startlndex], в эквивалентное значение типа uint и возвращает результат
public static ulong ToUInt64(byte[] value, intstartlndex) – Преобразует восемь байтов, начиная с элемента массива value[startlndex], в эквивалентное значение типа ulong и возвращает результат