Как использовать вложенные циклы для генерации всех возможных комбинаций элементов массива в C#? - PullRequest
0 голосов
/ 09 марта 2020

Я искал в Интернете и переполнении стека, но не нашел решения, которое искал.

Например, если у меня было {1, 2, 3, 4}, я хочу это вывод:

1234, 1243, 1423, 4123, 1324, 1342 etc.

Важно отметить, что я не хочу, чтобы программа отображала одну и ту же комбинацию более одного раза.

Вот что я придумал:

int[] pinCode = new int[5];
string z = "";

for (int i = 1; i < 4; i++)
{
    Console.Write("Numerical Digit {0}: ", i);
    pinCode[i] = Convert.ToInt32(Console.ReadLine());
}

for (int a = 1; a < 4; a++)
{
    z += pinCode[a].ToString();

    for (int b = 1; b < 4; b++)
    {
        z += pinCode[b].ToString();

        for (int c = 1; c < 4; c++)
        {
            z += pinCode[c].ToString();

            for (int d = 1; d < 4; d++)
            {
                z += pinCode[d].ToString();
                Console.WriteLine(z);
                z = "";
            }
        }
    }
}

Я просто не могу заставить его работать. Заранее спасибо.

Ответы [ 3 ]

0 голосов
/ 09 марта 2020

Вероятно, есть более эффективный способ сделать это, и использование рекурсии может избавить от жестких ограничений (4 варианта) этого решения. Вам нужно извлечь одно значение из вашего исходного списка, затем удалить эту опцию из копии списка и l oop через этот список таким же образом. Это означает, что ваш список будет меньше, чем глубже он будет в циклах. В конце концов у вас останется только один вариант, и вы сможете создать ответ и добавить его в список. После того, как все ответы добавлены, вы должны удалить дубликаты (разные), и все готово.

List<string> options = new List<string>() { "1", "2", "3", "4" };

List<string> answers = new List<string>();

foreach(var option in options)
{
    var options2 = options.ToList();
    options2.Remove(option);

    foreach(var option2 in options2)
    {
        var options3 = options2.ToList();
        options3.Remove(option2);

        foreach(var option3 in options3)
        {
            var options4 = options3.ToList();
            options4.Remove(option3);

            var option4 = options4.FirstOrDefault();
            answers.Add(string.Concat(option, option2, option3, option4));
        }
    }
}

answers = answers.Distinct().ToList();

var result = string.Join(",", answers);
0 голосов
/ 10 марта 2020

Поскольку каждый член является ди git, и вы будете выводить string, достаточно просто сохранить символы для каждого ди git.

var pinCode = new char[4];

Вам нужно 4 цифры, так что читайте в 4 строки и проверяйте каждый вход, чтобы убедиться, что это просто ди git. Сохраняйте каждый ди git в массиве pinCode.

for (int i = 0; i < 4; i++) {
    Console.Write("Numerical Digit {0}: ", i);
    string inLine;
    do {
        inLine = Console.ReadLine();
    } while (inLine.Length != 1 && !Char.IsDigit(inLine[0]));
    pinCode[i] = inLine[0];
    Console.WriteLine(inLine);
}

Поскольку вы будете наращивать (и разрушать) string символ за символом, использование StringBuilder гораздо эффективнее чем генерация string s, которые будут выброшены G C позже.

var onePermutation = new StringBuilder(4);

Нам нужна вложенная l oop для каждой выходной позиции, которая проходит через все возможные символы в каждом должность. В каждом вложенном l oop пропустите любые символы, уже использованные внешним l oop для более ранней позиции.

for (int a = 0; a < 4; a++) {
    onePermutation.Append(pinCode[a]);

    for (int b = 0; b < 4; b++) {
        if (a == b) // don't reuse a digit
            continue;

        onePermutation.Append(pinCode[b]);

        for (int c = 0; c < 4; c++) {
            if (c == a || c == b) // don't reuse a digit
                continue;

            onePermutation.Append(pinCode[c]);

            for (int d = 0; d < 4; d++) {
                if (d == c || d == b || d == a) // don't reuse a digit
                    continue;

                onePermutation.Append(pinCode[d]);
                Console.WriteLine(onePermutation.ToString());
                // after each character is used (output) remove it
                --onePermutation.Length;
            }
            --onePermutation.Length;
        }
        --onePermutation.Length;
    }
    --onePermutation.Length;
}

Если допустимо, чтобы pinCode s были одинаковыми, но все равно не требует дублирования вывода, вам придется кэшировать вывод и либо использовать Distinct в конце, либо проверять перед каждым выводом, что он ранее не выводился. (Спасибо @schwechel.)

0 голосов
/ 09 марта 2020

Вместо того, чтобы полностью «стереть» z в конце самого внутреннего l oop, просто сотрите только что добавленную букву. Сделайте то же самое для других циклов.

Обратите внимание, что вы даже не пытаетесь избегать дублирования букв в «комбинации», а тем более дублирующих комбинаций.

...