Почему и j--, и --j генерируют исключения в этом коде LINQ, а j-1 нет?

Я новичок в C# и практикуюсь, пишу решение классической задачи о 100 дверях. Приведенный ниже (и, вероятно, плохой) код решает проблему:

internal class Program
{
    private static void Main(string[] args)
    {
        var doors = new bool[100];
        var ints = new int[100];
        ints = Enumerable.Range(1, 100).ToArray();
        for (int i = 1; i <= 100; i++)
        {
           ints.Where(j => j % i == 0)
               .Select(j => j)
               .ToList()
               .ForEach(j => doors[j - 1] = !doors[j - 1]); //This is the relevant line.
        }
        Array.ForEach(doors, i => Console.WriteLine(i));
    }
}

Строка, на которую я поставил комментарий, меня удивила. Он отлично работает, но заменив его одним из следующих бросков System.IndexOutOfRangeException

.ForEach(j => doors[--j] = !doors[--j]);
.ForEach(j => doors[j--] = !doors[j--]);

Почему оба они недействительны, несмотря на то, что j - 1 в порядке? Насколько я понимаю, при любых обстоятельствах ровно один из --j и j-- будет эквивалентен j - 1.

Важный момент, который следует уточнить, прежде чем даже перейти к индексу за пределами границ: оператор приращения преобразуется в j = j - 1 либо до (--j), либо после (j--) переменной j, используемой в операторе. j - 1 == j - 1 ключевое отличие состоит в том, что присваивание j не происходит

Narish 20.11.2022 16:45
Как настроить Tailwind CSS с React.js и Next.js?
Как настроить Tailwind CSS с React.js и Next.js?
Tailwind CSS - единственный фреймворк, который, как я убедился, масштабируется в больших командах. Он легко настраивается, адаптируется к любому...
LeetCode запись решения 2536. Увеличение подматриц на единицу
LeetCode запись решения 2536. Увеличение подматриц на единицу
Увеличение подматриц на единицу - LeetCode
Переключение светлых/темных тем
Переключение светлых/темных тем
В Microsoft Training - Guided Project - Build a simple website with web pages, CSS files and JavaScript files, мы объясняем, как CSS можно...
Отношения &quot;многие ко многим&quot; в Laravel с методами присоединения и отсоединения
Отношения &quot;многие ко многим&quot; в Laravel с методами присоединения и отсоединения
Отношения "многие ко многим" в Laravel могут быть немного сложными, но с помощью Eloquent ORM и его моделей мы можем сделать это с легкостью. В этой...
В PHP
В PHP
В большой кодовой базе с множеством различных компонентов классы, функции и константы могут иметь одинаковые имена. Это может привести к путанице и...
Карта дорог Беладжар PHP Laravel
Карта дорог Беладжар PHP Laravel
Laravel - это PHP-фреймворк, разработанный для облегчения разработки веб-приложений. Laravel предоставляет различные функции, упрощающие разработку...
0
1
89
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий
Насколько я понимаю, при любых обстоятельствах ровно один из --j и j-- будет эквивалентен j - 1.

Нет, определенно нет.

Однако они терпят неудачу по разным причинам: один, когда j изначально равен 1, а другой, когда j изначально равен 100.

Сначала подумайте об этом:

.ForEach(j => doors[--j] = !doors[--j]);

Это уменьшает j дважды и в каждом случае использует значение j после того, как произошло уменьшение.

Сначала оценивается левый операнд, поэтому, когда j равно 1, это заканчивается оценкой индексов массива как:

doors[0] = !doors[-1];

Очевидно, что doors[-1] недействителен.

Теперь рассмотрим второй вариант:

.ForEach(j => doors[j--] = !doors[j--]);

Это снова уменьшает j дважды, но в каждой операции индексации массива используется значение j перед уменьшением. Итак, когда j равно 100, это приводит к оценке индексов массива как:

doors[100] = !doors[99];

На этот раз это doors[100], что недействительно.

В вашем рабочем коде вы используете j - 1 для обоих индексов, вообще не изменяя j, поэтому, когда j изменяется от 1 до 100, индексы массива, которые вы используете, изменяются от 0 до 99, что является допустимым.

Я бы настоятельно рекомендовал не использовать пре-/пост-инкременты/декременты в любом выражении или операторе, где вы используете измененную переменную более чем в одном месте, и определенно избегайте пре-/пост-инкрементов/декрементов одной и той же переменной несколько раз в одном и том же выражении. или заявление.

Другие вопросы по теме