Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to prevent a System.IndexOutOfRangeException in a LINQ WHERE?

Tags:

c#

split

linq

I'm facing this exception when I'm using String.Split with random strings.

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

linhas.Add("123;abc");
linhas.Add("456;def");
linhas.Add("789;ghi");
linhas.Add("chocolate");

var novas = linhas.Where(l => l.ToString().Split(';')[1]=="def");
like image 852
Helio Ferreira Avatar asked Jan 22 '16 14:01

Helio Ferreira


2 Answers

The last string "chocolate"doesn't contain a ";", so String.Split returns an array with a single string "chocolate". That's why you get the exception if you try to accesss the second.

You could use ElementAtOrDefault which returns null for strings instead:

var novas = linhas.Where(l => l.Split(';').ElementAtOrDefault(1) == "def");

A longer approach using an anonymous type:

var novas = linhas
    .Select(l => new { Line = l, Split = l.Split(';') })
    .Where(x => x.Split.Length >= 2 && x.Split[1] == "def")
    .Select(x => x.Line);
like image 73
Tim Schmelter Avatar answered Sep 22 '22 22:09

Tim Schmelter


I'm going to expand a little on Tim's answer and show a way to do a few extra things within your LINQ queries.

You can expand the logic within you Where clause to do some additional processes, which can make your code a bit more readable. This would be good for something small:

var novas = linhas.Where(l => 
            {
                var parts = l.Split(':');

                return parts.Length > 1 ? parts[1] == "def" : false;
            });

If you need multiple statements, you can wrap the body of your clause within curly braces, but then you need the return keyword.

Alternatively, if you have a lot of information that would make something inline like that unreadable, you can also use a separate method within your query.

public void FindTheStringImLookingFor()
{
    var linhas = new List<string>();

    linhas.Add("123;abc");
    linhas.Add("456;def");
    linhas.Add("789;ghi");
    linhas.Add("chocolate");

    var words = linhas.Where(GetTheStringIWant);
}

private bool GetTheStringIWant(string s)
{
    var parts = s.Split(':');

    // Do a lot of other operations that take a few lines.

    return parts.Length > 1 ? parts[1] == "def" : false;
}
like image 36
krillgar Avatar answered Sep 24 '22 22:09

krillgar