Рекурсия внутри цикла foreach

#c# #.net #for-loop #recursion

Вопрос:

У меня есть повторение в цикле — когда isAllowed = true — затем продолжайте следующую итерацию, но когда isAllowed значение false — тогда программа должна повторить генерацию случайных позиций, координат и проверить, верно ли значение isAllowed до.

Как сделать рекурсию в этом цикле для достижения этой цели?

 foreach (var fleet in groupedFleetsbySpaceshipCounts)
{
    var randomPositionX = new Random().Next(0, 9);
    var randomPositionY = new Random().Next(0, 9);

    var cords = int.Parse(randomPositionX.ToString()   randomPositionY);
    map.Location[cords].ActualFleetPosition = fleet.Key[i];
    var isAllowed = IsPositionAllowed(map, cords);
    if (isAllowed)
    {
        break;
    }
    else
    {
        randomPositionX = new Random().Next(0, 9);
        randomPositionY = new Random().Next(0, 9);

        cords = int.Parse(randomPositionX.ToString()   randomPositionY);
        map.Location[cords].ActualFleetPosition = fleet.Key[i];
        isAllowed = IsPositionAllowed(map, cords);
        if (isAllowed)
        {
            break;
        }
        else
        {
            //recursion
        }
    }
    i  ;
}
 

Комментарии:

1. var randomPositionX = new Random().Next(0, 9); var randomPositionY = new Random().Next(0, 9); не делайте этого, объявите случайные значения за пределами области, в которой они у вас есть, как статические (уровень класса), а затем используйте их в своем вызывающем коде.

2. Я предлагаю вам использовать simple для и перемещать/увеличивать итератор/индексатор, когда вы хотите выполнить следующую итерацию, если она автоматически не повторяет цикл.

3. Вы не должны создавать новые Random экземпляры в цикле — вам также не нужны отдельные экземпляры для генерации 2 значений.

Ответ №1:

Может быть, вы хотите чего-то подобного:

 var random = new Random();
foreach (var fleet in groupedFleetsbySpaceshipCounts)
{
    int coords;
    do {
        int randomPositionX = random.Next(0, 9);
        int randomPositionY = random.Next(0, 9);

        coords = 10 * randomPositionX   randomPositionY;
    } while (!IsPositionAllowed(map, coords));

    map.Location[coords].ActualFleetPosition = fleet.Key[i  ];
}
 

Т. е. вам нужна не рекурсия (т. Е. метод, который вызывает сам себя), а другой цикл, вложенный в первый.

Обратите внимание, что максимальное значение random.Next является исключительным. Итак, если вам нужны числа до 9 , вы должны использовать верхнее значение 10 . Кроме того, если значение меньше 0 , вы можете просто написать random.Next(10) .

Важно создать Random объект только один раз, потому что в противном случае у вас могут возникнуть разные случайные объекты, генерирующие одну и ту же псевдослучайную последовательность. Использование статического поля в вашем классе даже лучше, чем использование локальной переменной

 private static readonly _random = new Random();
 

Комментарии:

1. да — точно — это решает проблему — некоторое улучшение синтаксиса, и это будет работать

2. Но почему здесь операция = 10 * randompositionX randomPositionY? Намерение здесь — объединить как строку

3. пример, если a = 5 и b = 7 — тогда шнуров должно быть 57, но это вообще не имеет значения — координаты должны быть от 0 до 99

4. Что ж, 10 * 5 7 = 57. Не так ли? Если у вас есть координаты до 99, то используйте 100 * x y (= 507). Однако вместо этого вы можете использовать 2-мерный массив: T[,] a = new T[With, Height]; и получить к нему доступ a[x, y] . так было бы проще.

Ответ №2:

Я думаю, это должно сработать (отредактировано с некоторыми вашими комментариями, я не хотел касаться других вещей, а не вопроса).:

 var random = new Random();    
foreach (var fleet in groupedFleetsbySpaceshipCounts)
    {
        do
        {
            var randomPositionX = random.Next(0, 9);
            var randomPositionY = random.Next(0, 9);

            //Im not sure how you're managing this 'coords' map, but gonna just go to the point 
            var cords = int.Parse(randomPositionX.ToString()   randomPositionY);
            map.Location[cords].ActualFleetPosition = fleet.Key[i];
        } while (!IsPositionAllowed(map, cords));
        i  ;
    }
 

Если вы хотите, чтобы переменная ‘cords’ была доступна за пределами цикла do…while, вы можете смело объявить ее вне цикла (еще лучше, за пределами foreach).

Комментарии:

1. Вы уверены? — переменная cords находится внутри области видимости, поэтому она не определена вне {} в do while

2. ваше решение сработало как базовое — спасибо! — необходимо определить шнуры на один уровень выше.