Filter list with LINQ

S

Scott

In a Silverlight 2.0 application, I am attempting to filter a list of objects
using LINQ. The custom object named Incident has a property named “DOW†that
is of the type of DayOfWeek. The use case is that the user can select a
number of days of week and then the list of incidents is to be filtered. For
example, the user may select “Monday†and “Tuesdayâ€, the resulting list is to
only contain objects that have the DOW property of Monday and Tuesday.

I have been successful in selecting objects when there are a known number of
parameters, such as one day of the week; the challenge has to make this
dynamic. I have attempted to use the PredicateBuilder class but there is a
compile error when the List<>.Where used


Error 1 The type arguments for method
'System.Linq.Enumerable.Where<TSource>(System.Collections.Generic.IEnumerable<TSource>,
System.Func<TSource,int,bool>)' cannot be inferred from the usage. Try
specifying the type arguments explicitly. C:\
Test_Linq\Test_Linq\Page.xaml.cs 57 43 Test_Linq

Outlined below is the sample code.


public class Incident
{
public string FirstName;
public string LastName;
public DayOfWeek DOW;
public int TimeOfDay;
public int IncidentType;
}


public static class PredicateBuilder
{

public static Expression<Func<T, bool>> True<T>() { return f =>
true; }
public static Expression<Func<T, bool>> False<T>() { return f =>
false; }

public static Expression<Func<T, bool>> Or<T>(this
Expression<Func<T, bool>> expr1,

Expression<Func<T, bool>> expr2)
{
var invokedExpr = Expression.Invoke(expr2,
expr1.Parameters.Cast<Expression>());
return Expression.Lambda<Func<T, bool>>
(Expression.OrElse(expr1.Body, invokedExpr),
expr1.Parameters);
}

public static Expression<Func<T, bool>> And<T>(this
Expression<Func<T, bool>> expr1,

Expression<Func<T, bool>> expr2)
{
var invokedExpr = Expression.Invoke(expr2,
expr1.Parameters.Cast<Expression>());
return Expression.Lambda<Func<T, bool>>
(Expression.AndAlso(expr1.Body, invokedExpr),
expr1.Parameters);
}
}


//- Code to filter the list of incidents
List<Incident> incidents = new List<Incident>();

incidents.Add(new Incident() {FirstName= "s", LastName="m", DOW =
DayOfWeek.Friday});
incidents.Add(new Incident() {FirstName= "j", LastName="l", DOW=
DayOfWeek.Friday});
incidents.Add(new Incident() { FirstName = "Kim", LastName = "m", DOW =
DayOfWeek.Monday });
incidents.Add(new Incident() { FirstName = "x", LastName = "1", DOW =
DayOfWeek.Thursday });
incidents.Add(new Incident() { FirstName = "x", LastName = "2", DOW =
DayOfWeek.Tuesday });


List<DayOfWeek> listDayOfWeek = new List<DayOfWeek>();
listDayOfWeek.Add(DayOfWeek.Friday);
listDayOfWeek.Add(DayOfWeek.Monday);

var predictate = PredicateBuilder.False<Incident>();

foreach (DayOfWeek day in listDayOfWeek)
{
DayOfWeek queryDay = day;

predictate = predictate.Or(p => p.DOW == queryDay);
}

//Line that cannot compile
IQueryable<Incident> result = incidents.Where(predictate);
 
P

Peter Duniho

In a Silverlight 2.0 application, I am attempting to filter a list of
objects
using LINQ. The custom object named Incident has a property named “DOWâ€
that
is of the type of DayOfWeek. The use case is that the user can select a
number of days of week and then the list of incidents is to be
filtered. For
example, the user may select “Monday†and “Tuesdayâ€, the resulting list
is to
only contain objects that have the DOW property of Monday and Tuesday.

I have been successful in selecting objects when there are a known
number of
parameters, such as one day of the week; the challenge has to make this
dynamic. I have attempted to use the PredicateBuilder class but there
is a
compile error when the List<>.Where used [...]

Any particular reason you want to use your PredicateBuilder class? It
seems to me that a much simpler approach would be to use List.Contains()
in a lambda expression. For example:

IQueryable<Incident> result = incidents.Where(incident =>
listDayOfWeek.Contains(incident.DOW));

I'm sure we could figure out what's wrong with the PredicateBuilder
approach and fix it (based on the error message, probably simply by being
explicit about the type parameters, though I admit I didn't look very
closely), but I'm not sure that's really necessary. :)

Pete
 
S

Scott

Hello Pete,

Thank you for solving my problem; the solution you provide worked.

Scott

Peter Duniho said:
In a Silverlight 2.0 application, I am attempting to filter a list of
objects
using LINQ. The custom object named Incident has a property named “DOWâ€
that
is of the type of DayOfWeek. The use case is that the user can select a
number of days of week and then the list of incidents is to be
filtered. For
example, the user may select “Monday†and “Tuesdayâ€, the resulting list
is to
only contain objects that have the DOW property of Monday and Tuesday.

I have been successful in selecting objects when there are a known
number of
parameters, such as one day of the week; the challenge has to make this
dynamic. I have attempted to use the PredicateBuilder class but there
is a
compile error when the List<>.Where used [...]

Any particular reason you want to use your PredicateBuilder class? It
seems to me that a much simpler approach would be to use List.Contains()
in a lambda expression. For example:

IQueryable<Incident> result = incidents.Where(incident =>
listDayOfWeek.Contains(incident.DOW));

I'm sure we could figure out what's wrong with the PredicateBuilder
approach and fix it (based on the error message, probably simply by being
explicit about the type parameters, though I admit I didn't look very
closely), but I'm not sure that's really necessary. :)

Pete
 
L

Lingzhi Sun [MSFT]

Hi,

Peter, thank you very much for your quick reply. The Contains method is
definitely proper for this scenario.

Scott, the error is caused by improper type convert. The variable
incidents is in List<Incident> type (IEnumerable<Incident> in LINQ to
Object). And the Where extension method for incidents
(IEnumerable<Incident>) needs a parameter in type of Func<Incident, bool>
(We can treat it as a delegate function). However, the predicate is in
type of Expression<Func<Incident, bool>>, which is used in LINQ to SQL and
LINQ to Entities to build SQL command during runtime.

To fix it, we can call predicate.Compile() method to create the
corresponding Func<Incident, bool> object.
============================================================================
============
IEnumerable<Incident> result = incidents.Where(predicate.Compile());
============================================================================
============

For some supplements, we can use many different LINQ query methods for this
scenario, e.g. IEnumerable<T>.Any, IEnumerable<T>.Intersect, just like we
can use different SQL commands to query same set of data from database.
============================================================================
============
var result1 = incidents.Where(incident => listDayOfWeek.Any(day => day ==
incident.DOW));
var result2 = incidents.Where(incident => listDayOfWeek.Intersect(new
List<DayOfWeek) { incident.DOW }).Count() == 1);
============================================================================
============

Here are some additional references for us to understand the problem better:
http://msdn.microsoft.com/en-us/library/9eekhta0.aspx (IEnumerable<T>)
http://msdn.microsoft.com/en-us/library/bb351562.aspx (IQueryable<T>)
http://msdn.microsoft.com/en-us/library/bb549151.aspx (Func<T, TResult>)
http://msdn.microsoft.com/en-us/library/bb335710.aspx (Expression<T>)
http://blogs.msdn.com/charlie/archive/2006/10/31/the-linq-farm-part-ii.aspx
http://blogs.msdn.com/ericlippert/archive/2008/05/09/computers-are-dumb.aspx



If you have any questions regarding this case, please feel free to let me
know.


Best Regards,
Lingzhi Sun
Microsoft Online Community Support

Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).

==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/en-us/subscriptions/aa948868.aspx#notifications.

MSDN Managed Newsgroup support offering is for non-urgent issues where an
initial response from the community or a Microsoft Support Engineer within
2 business day is acceptable. Please note that each follow up response may
take approximately 2 business days as the support professional working with
you may need further investigation to reach the most efficient resolution.
The offering is not appropriate for situations that require urgent,
real-time or phone-based interactions. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/en-us/subscriptions/aa948874.aspx
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
S

Scott

Hello Lingzhi,

Thanks for the detailed information on this problem. I am new to LINQ and
your response has helped to clear up some questions I had.

Scott
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top