Select parsed int, if string was parseable to int

So I have an IEnumerable<string> which can contain values that can be parsed as int, as well as values that cannot be.

As you know, Int32.Parse throws an exception if a string cannot be changed to an int, while Int32.TryParse can be used to check and see if the conversion was possible without dealing with the exception.

So I want to use a LINQ query to one-liner parse those strings which can be parsed as int, without throwing an exception along the way. I have a solution, but would like advice from the community about whether this is the best approach.

Here's what I have:

int asInt = 0;
var ints = from str in strings
           where Int32.TryParse(str, out asInt)
           select Int32.Parse(str);

So as you can see, I'm using asInt as a scratch space for the call to TryParse, just to determine if TryParse would succeed (return bool). Then, in the projection, I'm actually performing the parse. That feels ugly.

Is this the best way to filter the parseable values in one-line using LINQ?


Solution 1:

It's hard to do that in query syntax, but it's not too bad in lambda syntax:

var ints = strings.Select(str => {
                             int value;
                             bool success = int.TryParse(str, out value);
                             return new { value, success };
                         })
                  .Where(pair => pair.success)
                  .Select(pair => pair.value);

Alternatively, you may find it worth writing a method which returns an int?:

public static int? NullableTryParseInt32(string text)
{
    int value;
    return int.TryParse(text, out value) ? (int?) value : null;
}

Then you can just use:

var ints = from str in strings
           let nullable = NullableTryParseInt32(str)
           where nullable != null
           select nullable.Value;

Solution 2:

It's still two codelines, but you can shorten up your original a little:

int asInt = 0;
var ints = from str in strings
           where Int32.TryParse(str, out asInt)
           select asInt;

Since the TryParse already runs at the time of the select, the asInt variable is populated, so you can use that as your return value - you don't need to parse it again.