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

How to get an a Task similar to what StreamReader.ReadToEndAsync() returns but not started by default?
Concatenating int and list in c# [closed]
Invoking a webservice on a particular sql db transaction
Unable to cast object of type 'ASP._Page__ViewStart_cshtml' to type 'System.Web.WebPages.StartPage'. Error
Send Google Mail in C# failed because of 403 Insufficient permissions
DocuSign - RestApi v2 - download document using C#
How to keep emails in same conversations in microsoft outlook 2016 after subject change?
How to convert List<string> into String of Comma Separated Quotes from List [duplicate]
Any C# library to do webrequest similar to httpwebrequest but not throwing exceptions
Linq - get unavailable IDs in a list using linq
ASMX Service XML request deserializing partially
Different transaction commits at same time
Webapi token based authentication. Some guidance needed [on hold]
How to make a dynamic label using ASP.NET?
Selecting drop down option using XPath - Visual Studio
NetworkStream write() with event name

Categories

HOME
airflow
google-cloud-pubsub
teradata
jenkins-pipeline
crm
localhost
mediarecorder
jshell
meson-build
pip
rtc
box-api
segmentation-fault
wowza
derby
opengrok
appsettings
web-parts
printf
computation-theory
klipfolio
bootstrap-accordion
meteor-accounts
kundera
jbossfuse
2checkout
akamai
tikz
jql
ilog
lighting
form-fields
linkurious
test-kitchen
nshttpurlresponse
amazon-fire-tv
react.rb
import.io
openidm
selection-sort
programming-pearls
reloaddata
huawei
dbi
disconnect
key-value-store
python-rq
boost-propertytree
cexception
wordpress-plugin
jersey-test-framework
kramdown
jcomponent
jain-sip
identifying
joomla3.3
tokudb
vectordrawable
radgrid
chunks
frisby.js
diffmerge
lwuit
sat4j
nest-initiative
webshim
traceur
lettuce
rssi
elixir-framework
data-layers
php-amqplib
xtify
mysql-error-1146
dylan
infomaker
zend-db-table
nsnumber
record-locking
wpa
source-depot
jython-2.5
google-checkout
simplemembership
auctex
database-restore
urlfetch
win-prolog
jmesa
scsf
rjs
qvariant
lgpl
jquery-attributes
file-storage
datadude
script-tag
bootstrap-protocol

Resources

Database Users
RDBMS discuss
Database Dev&Adm
javascript
java
csharp
php
android
javascript
java
csharp
php
python
android
jquery
ruby
ios
html
Mobile App
Mobile App
Mobile App