Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sequence contains no elements

Tags:

c#

random

linq

Can someone explain me why the following LINQ query throws an InvalidOperationException?
(Don't say that the list has no elements,the value that I'm looking for always exists in the collection)

class Program
{
     static int lastNumber;
     static void Main()
     {
          int loopCount = 100; int minValue = 1; int maxValue = 10000;
          var numbers = Enumerable.Range(minValue, maxValue).ToList();//or ToArray();
          Random random = new Random();

          for (int i = 0; i < loopCount; i++)
          {
              //.First() throws the exception but it is obvious that the value exists in the list
              int x = numbers.Where(v => v == NewMethod(minValue, maxValue, random)).First();
          }
          Console.WriteLine("Finished");
          Console.ReadLine();

     }

     private static int NewMethod(int minValue, int maxValue, Random random)
     {
         var a1 = random.Next(minValue + 1, maxValue - 1);
         lastNumber = a1;
         return a1;
     }
}

The problem appears only when I call NewMethod inside my lambda expession.
If do this it works

int temp=NewMethod(minValue, maxValue, random);
int x = numbers.Where(v => v == temp).First();

I added the lastNumber field to help debug the code,you can see that the value exists in the collection when it crashes

PS
The problem is not the random variable,I removed the parameter and create a new local random inside the method but the problem still exists

Update

It turns out that you don't need the loop to make it crash. If you run the program many times you will get the error again

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
class Program
{
    static int lastNumber;
    static void Main()
    {
        int minValue = 1, maxValue = 100000;
        var numbers = Enumerable.Range(minValue, maxValue).ToArray();
        //Crashes sometimes
        int x = numbers.Where(v => v == NewMethod(minValue, maxValue)).First();
        Console.WriteLine("Finished");
        Console.ReadLine();
     }

     private static int NewMethod(int minValue, int maxValue)
     {
          Random random = new Random();
          var a1 = random.Next(minValue + 1, maxValue - 1);
          lastNumber = a1;
          return a1;
      }
 }
like image 348
George Vovos Avatar asked Jun 18 '15 21:06

George Vovos


People also ask

What does sequence contains no elements mean in LINQ?

Fixing LINQ Error “Sequence contains no elements” [C#, LINQ] When you query a LINQ data source with the Single() method call you may get the exception “System.InvalidOperationException: Sequence contains no elements”. This exception is raised when there are no records that matches to the criteria specified in the LINQ query.

Why do I get system invalidoperationexception sequence contains no elements?

When you query a LINQ data source with the Single () method call you may get the exception “System.InvalidOperationException: Sequence contains no elements”. This exception is raised when there are no records that matches to the criteria specified in the LINQ query.

Why does single () throw an error when returning a sequence?

As per the exception - The sequence returned in step1 contains no elements. Single () tries to retrieve an element from the sequence returned in step1 which contains no elements. Since Single () is not able to fetch a single element from the sequence returned in step1, it throws an error.

What is single or default error in LINQ?

This exception is raised when there are no records that matches to the criteria specified in the LINQ query. For example the following LINQ query raises the exception if the where criteria does not match with any records in the data source To solve the problem replace the method Single () call with SingleOrDefault () method.


2 Answers

@Oleg is right, but here's why it's the problem.

Where scans through the list looking for elements that match the given criteria. In this case the criteria changes for each element. If you made the problem smaller, say an array of 5 elements:

List<Int32> (5 items)
1 
2 
3 
4 
5 

And then looped through looking for a value that matches some random number (x is Item[i] and r is a random number):

Item 1: x = 1, r = 2  // fail
Item 2: x = 2, r = 3  // fail
Item 3: x = 3, r = 2  // fail
Item 4: x = 4, r = 3  // fail
Item 5: x = 5, r = 2  // fail

Note that no item match that particular random number, so no item matched the criteria and First throws an exception!

The fix, as you have discovered, is to generate the random number before the enumeration:

int temp=NewMethod(minValue, maxValue, random);  // say 2

Item 1: x = 1, temp = 2  // fail
Item 2: x = 2, temp = 2  // success!

Side note:

It's a bit misleading to use maxValue here:

 Enumerable.Range(minValue, maxValue)

Since the second parameter to Enumerable.Range is the length of the resulting collection, not the max value. In this case it works because you're starting at 1 but the results would be unexpected if you used, say 99 and 100 - you'd get a range from 99 to 198.

like image 82
D Stanley Avatar answered Oct 11 '22 18:10

D Stanley


It's because NewMethod invokes on every iteration and every time generates new random number.

But in this code at first generates number and then compares to each element of numbers collection.

int temp=NewMethod(minValue, maxValue, random);
int x = numbers.Where(v => v == temp).First();
like image 37
Oleg Avatar answered Oct 11 '22 16:10

Oleg