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

.net core & .net framework in the same team
I have an error when the code first tries to generate the code it says unable to determine the principal end of an association
AggressiveInlining doesn't exist
ASP:Dropdown List producing duplicate value on button click while data binding
Unicode characters not displaying properly in the Visual Studio Code's integrated terminal
Set Border Transparent for a disabled Button in Windows 8.1 Universal application
FileNotFound Exception when referencing LinqPad.exe
Dependency Injection in Unit Tests
EWS managed API 2.2 StreamingSubscription exception
Weird Selenium Click Behaviour C#
Unity custom UnityEngine.UI button inspector
How to Generate unit tests in visual studio 2015,x64 configuration
LINQ Any() not working as expected
how is repository pattern really done?
Trying to retrieve form response in C# .aspx web form
get properties with reflection from an object in shared/pcl project

Categories

HOME
logging
skype-for-business
msbuild
twitter-bootstrap
cluster-analysis
aix
latex
gaussian
azure-database-mysql
jquery-plugins
stdout
arguments
symfony-sonata
comments
travis-ci-cli
android-webview
obd-ii
ios-universal-links
rename
google-app-maker
velocity
mbed
tmux
webseal
versioning
civicrm
scotty
descriptor
datazen-server
ejb-3.1
gnu-screen
procedural-generation
v4l2
gsuite
grunt-contrib-uglify
datanucleus
smart-device
android-6.0-marshmallow
emr
hierarchy
jql
kubectl
unity3d-5
rtos
restler
offset
apache-falcon
ponylang
javafxports
rythm
stochastic-process
rtsp
mybatis-generator
lfe
head
synchronized
google-chrome-storage
remap
runtime-permissions
cancan
activesupport
rmq
blitz3d
settext
networkstream
deck.js
cherry-pick
gtkwave
ruby-1.8.7
php-gd
log4cxx
properties-file
textblob
nmock
skview
bungeecord
firebase-tools
mri
applinks
random-access
jsonmodel
information-hiding
report-builder2.0
serializer
sendy
nvcc
php-amqplib
dylan
ie-developer-tools
static-class
extensibility
forward-declaration
azure-scheduler
gwt2
ncml
moonscript
nsregularexpression
cryptarithmetic-puzzle
linear-interpolation
android-memory
nserror
wxperl
towerjs
virtual-printer
openwrap
sipdroid
conditional-operator
text-manipulation
simultaneous
table-valued-parameters
mysql-pconnect
manuals
script-tag

Resources

Mobile Apps Dev
Database Users
javascript
java
csharp
php
android
MS Developer
developer works
python
ios
c
html
jquery
RDBMS discuss
Cloud Virtualization
Database Dev&Adm
javascript
java
csharp
php
python
android
jquery
ruby
ios
html
Mobile App
Mobile App
Mobile App