Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Why do both j– and –j throw exceptions in this LINQ code, but j – 1 does not?

I’m new to C# and practising by writing a solution to the classic 100 doors problem. The below (and probably bad) code solves the problem:

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));
    }
}

The line that I’ve put the comment on has surprised me. It works perfectly fine, but replacing it with either of the below throws System.IndexOutOfRangeException

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

Why are both of these invalid despite j - 1 being perfectly fine? It’s my understanding that, in all circumstances, exactly one of --j and j-- will be equivalent to j - 1.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

It’s my understanding that, in all circumstances, exactly one of –j and j– will be equivalent to j – 1.

No, definitely not.

The two fail for different reasons though – one when j is initially 1, and the other when j is initially 100.

First consider this:

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

That decrements j twice, and in each case uses the value of j after the decrement has happened.

The left hand operand is evaluated first, so when j is 1, this ends up evaluating array indexes as:

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

Obviously, doors[-1] is invalid.

Now let’s consider the second option:

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

This again decrements j twice, but in each array indexing operation uses the value of j before the decrement. So when j is 100, this ends up evaluating array indexes as:

doors[100] = !doors[99];

This time it’s doors[100] which is invalid.

In your working code, you’re using j - 1 for both indexes, without modifying j at all, so as j goes from 1 to 100, the array indexes you’re using go from 0 to 99, which are valid.

I would strongly advise against using pre/post-increments/decrements in any expression or statement where you use the modified variable in more than one place – and definitely avoid pre/post-increments/decrements of the same variable multiple times in the same expression or statement.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading