Петля над массивом неизвестного измерения в C#

Предыдущий пост Loop над записями в массиве неизвестной длины в 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);
}

Один из самых больших трюков здесь - это то, что вы хотите делать со значениями. В этом примере я решил создать строку, показанную на картинке. Он отображает каждый размер массива с отступом и окружен фигурными фигурными скобками, несколько похожим на предыдущий код, который инициализирует массив. Самый внутренний уровень массива отображается в одной строке со значениями, заключенными в круглые скобки.

предыдущий пост < / a> использует вложенные петли для для итерации по размерам двумерного массива. Поскольку мы не знаем, сколько измерений имеет массив в этом примере, эта стратегия не будет работать. Вы могли бы попытаться сделать огромную серию вложенных циклов, а затем сделать ненужными ничего не делать, но это было бы сложно, запутанно и негибко.

В этом примере используется рекурсия для посещения каждого из параметров массива. Когда он посещает последнее измерение, код создает строку, содержащую значения в одной строке, как показано на рисунке. Этот метод является гибким и не настолько жестким, хотя он может быть немного запутанным.

В следующем коде показан метод 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;
}

Этот метод довольно прост. Он получает верхнюю границу для окончательного измерения и петли над своим диапазоном, соединяя значения массива.

Источник: http://csharphelper.com/blog/2016/12/loop-over-an-array-of-unknown-dimension-in-c/

1 Звезда2 Звезды3 Звезды4 Звезды5 Звезд (Пока оценок нет)
Adblock
detector