c#


Linq: Filter list of type A based on an object of type A?


I have a List of objects of type Foo, and another instance of an object of type Foo. I would like to use linq to filter the list based on the non-null properties of the instance.
class Foo {
public int ID;
public string Description;
public long Location;
}
Foo fooFilter = new Foo() {
ID = null,
Description = null,
Location = 1
}
List<Foo> fooList = new List<Foo>();
fooList.Add(new Foo(){ID = 1, Description = "one", Location = 1});
fooList.Add(new Foo(){ID = 2, Description = "two", Location = 0});
fooList.Add(new Foo(){ID = 3, Description = "three", Location = 1});
List<Foo> filteredFooList = fooList.Where(???);
I want to somehow use fooFilter to query fooList and fill filteredFooList with:
[
{ID = 1, Description = "one", Location = 1},
{ID = 3, Description = "three", Location = 1}
]
EDIT:
I was trying to be brief to make the question more clear, but I might have left of important information. In my actual program, List<Foo> is a large result from a database (over 40k entries). I'm trying to make a controller method (MVC) which can take any combination of parameters that would match the field names of an entity framework object. So <Foo> is a EF record type. So I'm trying to avoid having to explicitly list all the (15 or so) fields that can be filtered on in the controller:
public class Home : Controller
{
public ActionResult FilteredFooList(int ID, string Description, long Location, etc, etc, etc)
{
}
}
And do something more like:
public class Home : Controller
{
public ActionResult FilteredFooList(Foo filterObj)
{
}
}
Maybe this isn't possible or a good idea?
If you only want to filter out non instanciated properties, you don't need a filter.
class Foo
{
public int ID;
public string Description;
public long Location;
public bool IsInstanciated()
{
return this.ID != default(int) && this.Description != default(string) && this.Location != default(long);
}
}
List<Foo> filteredFooList = fooList.Where(f => f.IsInstanciated());
If you really need to use that instanciated class as a filter, I'd suggest you to use IEquatable<T>
class Foo : IEquatable<Foo>
{
public int ID;
public string Description;
public long Location;
public bool Equals(Foo other)
{
// Whatever your logic is
return this.Description == other.Description && this.ID == other.ID && this.Location == other.Location;
}
}
List<Foo> filteredFooList = fooList.Where(f => !f.Equals(fooFilter));
Assuming you can change your value types to be nullable:
class Foo {
public int? ID;
public string Description;
public long? Location;
}
Then you can use some extensions:
public static class Ext {
public static bool EqualOrNull<T>(this T? value, T? filter) where T : struct, IComparable {
return (filter == null) || (value.Value.CompareTo(filter.Value) == 0);
}
public static bool EqualOrNull<T>(this T value, T filter) where T : class, IComparable {
return (filter == null) || (value.CompareTo(filter) == 0);
}
}
To do this:
var filteredFooList = fooList.Where(f => f.ID.EqualOrNull(fooFilter.ID) && f.Description.EqualOrNull(fooFilter.Description) && f.Location.EqualOrNull(fooFilter.Location));
If you wanted something truly generic (e.g. not dependent on knowing the field names) you would need to step into the world of Reflection.
By looking at your expected output, it appears that you want to filter fooList so that you get all items that have the same Location as your fooFilter object. If that's what you're asking, you can do this:
List<Foo> filteredFooList = fooList.Where(item => item.Location == fooFilter.Location);
Don't paint yourself into a corner by adding unnecessary properties to your data objects, they should stay data objects. You're effectively trying to build a dynamic query where you want to conditionally filter by a list of conditions. There are patterns to do this.
Start with a base query, then determine if you want to filter by one of the properties. Do the same with the rest of the other properties. By the time you reach the end, you could then just gather the results.
var filter = new Foo
{
ID = null,
Description = null,
Location = 1,
};
var data = new List<Foo>
{
new Foo { ID = 1, Description = "one", Location = 1 },
new Foo { ID = 2, Description = "two", Location = 0 },
new Foo { ID = 3, Description = "three", Location = 1 },
};
var query = data.AsEnumerable();
if (filter.ID != null)
query = query.Where(x => x.ID == filter.ID);
if (filter.Description != null)
query = query.Where(x => x.Description == filter.Description);
if (filter.Location != null)
query = query.Where(x => x.Location == filter.Location);
var result = query.ToList();
This assumes that ID and Location are actually nullable just like your example implies.
public class Foo
{
public int? ID { get; set; }
public string Description { get; set; }
public long? Location { get; set; }
}

Related Links

Bot Framework Channel Emulator has invalid channel ID?
Memory trouble with recursive functions C#
cannot evaluate the item metadata
What Dependency Injection Framework Does ASP.Net Core Use?
Retrieve Type Foo<Bar> from name when Bar is created from TypeBuilder
Is it possible to create a “perfect forwarding” generic collection in C#?
Forcing the UI Rendering after I performed an action in UWP
Coding: changing a and b values [closed]
Incorrect syntax near 'ENTUserAccount'
Change the color of the Grid Cell in C#
DynamicResource doesn't show the correct value
how to pass unicode in asp.net web api to sql server database [duplicate]
C# - Access property in inheriting class
Sending bulk push notifications using FCM in C#?
Retrieve data from jQuery POST in aspx
strange behaviour of MVC routing

Categories

HOME
asterisk
repository
javafx
xamarin.forms
python-requests
file-upload
c++builder
skypedeveloper
conceptual
mifare
x86-64
magento-1.9.2.1
spss
assign
css-selectors
ms-access-2010
angularjs-directive
genexus
yacc
obd-ii
oms
saucelabs
console-application
web-parts
google-street-view
loader
draw2d
glibc
include-path
vala
beaker-notebook
google-drive-android-api
procedural-generation
windowserror
waterfall
jira-zephyr
pixels
android-6.0-marshmallow
launchd
arp
multilanguage
circle
ports
microstrategy
zimbra
javax
geocomplete
asp.net-webhooks
redhat-brms
ngrok
office-interop
bootstrap-carousel
inner-join
ocamlbuild
spring-webflow-2
ng-class
dotnet-cli
node-java
intermediate-language
hellosign
multi-select
racket-student-languages
scikit-image
dimensionality-reduction
x12
jspx
require-handlebars
db2-zos
avi
web-optimization
stdlist
google-finance-api
jcomponent
recode
self-join
borland-c++
pdcurses
web-standards
page-refresh
asp.net-2.0
mri
conditional-comments
rails-migrations
vbaccelerator
node-amqp
lastinsertid
google-oauth-java-client
usersettings
wpd
kademlia
tasklist
openafs
shapado
sup
nsscrollview
socketasynceventargs
virtual-printer
cherokee
jquery-click-event
cryptolicensing
rollover
database-agnostic
pkcs#7
vista64
stackless
paperless

Resources

Encrypt Message