mulitple where or conditions in Linq to object

I have a list of TelephoneDataType objects

 public List<TelephoneDataType> Values { get; set; }

The TelephoneDataType object has a enum property called ChartType

public class TelephoneDataType
{
  public ChartType ChartId { get; set; }
}

So from this Values List, I want to pull out all TelephoneDataType objects that has ChartId set to any of the following values:

Answered Abandoned ExpectedWait InQueue

Here is my failed attempt

var items = telephoneData.Values
                    .Where(c => c.ChartId == Enums.ChartType.Answered)
                    .Where(c => c.ChartId == Enums.ChartType.Abandoned)
                    .Where(c => c.ChartId == Enums.ChartType.ExpectedWait)
                    .Where(c => c.ChartId == Enums.ChartType.InQueue).ToArray();

Upvotes: 1

Views: 79

Answers (5)

Roman Chichin
Roman Chichin

Reputation: 36

I guess that the best way, which will help you not only in this situation - to write a special extension method for enums:

 public static class EnumExtensions
 {
        public static bool InSet<T>(this T target, params T[] possibleValues) where T : struct 
        {
            return possibleValues.Contains(target);
        }
    }

And solution is:

var items = telephoneData.Values
                .Where(c => c.ChartId.InSet(Enums.ChartType.Answered, 
                                            Enums.ChartType.Abandoned,
                                            etc...);

Upvotes: 0

Each Where returns a filtered enumerable, so after your first Where you are only left with a single ChartType. You must combine the conditions into a single Where operation like this:

var items = (telephoneData.Values
                    .Where(c => c.ChartId == Enums.ChartType.Answered || c.ChartId == Enums.ChartType.Abandoned || c.ChartId == Enums.ChartType.ExpectedWait || c.ChartId == Enums.ChartType.InQueue)
                    .ToArray());

Upvotes: 0

Dmitrii Bychenko
Dmitrii Bychenko

Reputation: 186803

I'd rather implement an extension method for Enums.ChartType e.g.

  public static class EnumsChartTypeExtensions {
    //TODO: find out a proper name for the method
    public static Boolean IsOnLine(this Enums.ChartType value) { 
      return value == Enums.ChartType.Answered || 
             value == Enums.ChartType.Abandoned ||
             value == Enums.ChartType.ExpectedWait ||
             value == Enums.ChartType.InQueue; 
    }
  }

And so your Linq will be far more readable:

  var items = telephoneData.Values
    .Where(c => c.ChartId.IsOnLine())
    .ToArray();

Yet another advantage of the solution is if you add some statuses into Enums.ChartType (e.g. WaitingForAnswer) all you'll have to do is to update the extension methods only (and not all your Linq within the whole application)

Upvotes: 1

Johan
Johan

Reputation: 8276

Your current solution is doing &&'s between your .Where clauses. You need to make them ||'s by doing one of the following

var items = telephoneData.Values
                         .Where(c => c.ChartId == Enums.ChartType.Answered
                                  || c.ChartId == Enums.ChartType.Abandoned
                                  || c.ChartId == Enums.ChartType.ExpectedWait
                                  || c.ChartId == Enums.ChartType.InQueue
                               )
                         .ToArray();

or (which is more readable and easier to update/maintain)

  var myFilterList = new [] 
  {
      Enums.ChartType.Answered,
      Enums.ChartType.Abandoned,
      Enums.ChartType.ExpectedWait,
      Enums.ChartType.InQueue
  };

   var items = telephoneData.Values
                            .Where(c => myFilterList.Contains(c.ChartId)
                            .ToArray();

Also remember that your .Where clauses aren't executed immediately.
They are only executed when you do a .ToList, .ToArray, etc. You can read more about that here: https://msdn.microsoft.com/en-us/library/vstudio/bb738633(v=vs.100).aspx

Upvotes: 3

theB
theB

Reputation: 6738

Think through your query step by step. First you get all charts with ID Answered. You then take that list and filter it for Abandoned, but the entries are all Answered already.

Try using the or operator.

var items = telephoneData.Values
                .Where(c => c.ChartId == Enums.ChartType.Answered ||
                            c.ChartId == Enums.ChartType.Abandoned ||
                            c.ChartId == Enums.ChartType.ExpectedWait ||
                            c.ChartId == Enums.ChartType.InQueue).ToArray();

Upvotes: 0

Related Questions