Петля над массивом неизвестного измерения в C#
Предыдущий пост
В этом примере используется следующий код для инициализации трехмерного массива и отображения его текстового представления. Метод ArrayTextValue, который описывается в скором времени, пересекает массив для создания текстового представления.
private void Form1_Load(object sender, EventArgs e) { // Список значений в массиве неизвестных измерений. string[, ,] values3 = { { { "(0, 0, 0)", "(0, 0, 1)" }, { "(0, 1, 0)", "(0, 1, 1)" }, { "(0, 2, 0)", "(0, 2, 1)" }, }, { { "(1, 0, 0)", "(1, 0, 1)" }, { "(1, 1, 0)", "(1, 1, 1)" }, { "(1, 2, 0)", "(1, 2, 1)" }, }, { { "(2, 0, 0)", "(2, 0, 1)" }, { "(2, 1, 0)", "(2, 1, 1)" }, { "(2, 2, 0)", "(2, 2, 1)" }, }, { { "(3, 0, 0)", "(3, 0, 1)" }, { "(3, 1, 0)", "(3, 1, 1)" }, { "(3, 2, 0)", "(3, 2, 1)" }, }, }; txtValues.Text = ArrayTextValue(values3); txtValues.Select(0, 0); }
Один из самых больших трюков здесь - это то, что вы хотите делать со значениями. В этом примере я решил создать строку, показанную на картинке. Он отображает каждый размер массива с отступом и окружен фигурными фигурными скобками, несколько похожим на предыдущий код, который инициализирует массив. Самый внутренний уровень массива отображается в одной строке со значениями, заключенными в круглые скобки.
В этом примере используется рекурсия для посещения каждого из параметров массива. Когда он посещает последнее измерение, код создает строку, содержащую значения в одной строке, как показано на рисунке. Этот метод является гибким и не настолько жестким, хотя он может быть немного запутанным.
В следующем коде показан метод ArrayTextValue, который создает текстовое представление.
// Возвращаем строку, содержащую значения в // массив неизвестного измерения. private string ArrayTextValue(Array values) { // Делаем массив для хранения индексов. int num_dimensions = values.Rank; int[] indices = new int[num_dimensions]; // Получить и отобразить текстовое представление массива. return GetArrayTextValues(values, 0, indices, 0); }
Этот код использует свойство массива Rank, чтобы получить количество измерений массива. Затем он заставляет массив удерживать индексы для каждого измерения. Например, если есть 4 измерения, и массив индексов содержит значения {2, 3, 3, 5}, тогда код рассматривает значения массива [2, 3, 3, 5] . р>
Затем метод вызывает метод GetArrayTextValues для выполнения реальной работы, передавая ему массив, количество, на которое он должен отступать от текста (изначально 0), массива индексов, индекса в массив, который GetArrayTextValues должен учитывать. Этот код передает 0 для окончательного аргумента, поэтому GetArrayTextValues начинается с назначения первого индекса в массиве индексов.
В следующем коде показан метод GetArrayTextValues.
// Рекурсивно возвращать строковое представление // значения в массиве из данной позиции вперед. private string GetArrayTextValues(Array values, int indent, int[] indices, int dimension_num) { string spaces = new string(' ', indent); string txt = spaces + "{"; // Перебираем значения по этому индексу. int max_index = values.GetUpperBound(dimension_num); for (int i = 0; i <= max_index; i++) { indices[dimension_num] = i; // Смотрите, является ли это последним измерением. if (dimension_num == values.Rank - 2) { // Это следующий за последним измерением. Верните значение. txt += Environment.NewLine + spaces + " { " + GetArrayInnermostData(values, indices) + " }"; } else { // Это не последнее измерение. Recurse. txt += Environment.NewLine + GetArrayTextValues(values, indent + 4, indices, dimension_num + 1); } } txt += Environment.NewLine + spaces + "}"; return txt; }
Этот метод отвечает за рекурсию. Он начинается с создания строки, которая правильно отступом для этого уровня массива. Затем он получает верхнюю границу для рассматриваемого измерения и делает переменную i петлей над диапазоном значений, допустимых для этого измерения. Для каждого значения индекса в этом измерении программа проверяет, рассматривает ли он измерение второго по величине массива.
Если это второе измерение, код вызывает метод GetInnermostData, чтобы получить представление последнего измерения данных - измерение, которое содержит фактические данные, которые должны отображаться в одна строка вывода.
Если это не второе измерение, метод вызывает себя рекурсивно для обработки следующего измерения массива.
Следующий код показывает метод GetArrayInnermostData.
// Возвращает самую внутреннюю строку данных, разделенную пробелами. private string GetArrayInnermostData(Array values, int[] indices) { string txt = ""; // Получить индекс последнего измерения. int dimension_num = values.Rank - 1; // Сопоставляем значения. int max_index = values.GetUpperBound(dimension_num); for (int i = 0; i <= max_index; i++) { indices[dimension_num] = i; txt += " " + values.GetValue(indices).ToString(); } txt = txt.Substring(1); return txt; }
Этот метод довольно прост. Он получает верхнюю границу для окончательного измерения и петли над своим диапазоном, соединяя значения массива.