Poma
Poma

Reputation: 8494

How to select *some* items with LINQ?

how to write this function in LINQ?

public List<TResult> select(List<string> source)
{
    List<TResult> result = new List<TResult>();
    foreach (var a in source)
    {
        try { result.Add(TResult.Parse(a)); }
        catch { }
    }
    return result;
}

I want to select only such items that are convertable to TResult. TResult.Parse() returns new instance of TResult.

Upvotes: 2

Views: 998

Answers (4)

Rup
Rup

Reputation: 34418

Not quite LINQ, but you can write an iterator-yield solution to do it in a single pass:

public static IEnumerable<TResult> SelectParse<TResult>(
                                       this IEnumerable<string> source)
{
    foreach(string a in source)
    {
        TResult parsed;
        try
        {
            parsed = TResult.Parse(a);
        }
        catch
        {
            continue;
        }
        yield return parsed;
    }
}

and so List<TResult> results = source.SelectParse<TResult>().ToList();

But if your Parse method frequently raises exception then you probably want to write a TryParse version that returns a success / failure bool instead. (That wouldn't help writing the LINQ, though.)


Fixed the yield-inside-try - thanks. The minor advantage of this solution over the accepted one is that it supports Parse returning null as a valid result, but I doubt you'd ever need / want that.

Upvotes: 1

Richard Friend
Richard Friend

Reputation: 16018

Do you have access to the class that defines Parse, if so does it have a TryParse method or can you create one..

    public class TResult
    {
        public static  TResult Parse(string text)
        {
            //Parse here
            return new TResult();
        }
        public static bool TryParse(string text, out TResult mc)
        {
            try
            {
                mc = Parse(text);
                return true;
            }
            catch(Exception ex)
            {
                mc = null;
                return false;
            }
        }
    }

Then

public IEnumerable<TResult> Select(IEnumerable<string> result)
    {
        return result.Select(r=>
            {
                TResult item = null;
                TResult.TryParse(r, item);
                return item;
            }).Where(item=>item != null);
    }

Upvotes: 0

Robert Giesecke
Robert Giesecke

Reputation: 4314

You can pass statements not just lambdas to the LINQ methods:

var results = source.Select(item => 
  {
    try
    { 
      return TResult.Parse(item);
    }
    catch
    { return null; }
  }).Where(result => result != null).ToList();

Upvotes: 5

Jaimal Chohan
Jaimal Chohan

Reputation: 8645

One way would be

List<TResult> result = source.Where(TResult.Parse(a) != default(TResult)).ToList()

But that assumes that the Parse() method does not throw an exception

Upvotes: 0

Related Questions