Compare predicates - c#

I have a list of predicates
public List<Func<Album, bool>> Predicates { get; set; }
I'd like to check if a list contains specific predicate.
What I do is this :
bool check = Predicates.Contains(x=>x.AlbumName == "Winter");
But this always returns false even though there is such a predicate in the list. I assume it is because predicates are anonymous methods and each is kind of unique, but still is it possible to compare them somehow?

I'm afraid the answer is basically "no". If you had expression trees instead of delegates then you could probably compare those with effort, but basically you've got references to separate methods. You'd need to inspect the IL inside the methods to compare whether or not they're the same.
Of course if you have a set of objects on which the predicates operate, you could find out whether you have any predicates which matches the same subset as your "target" predicate, but that's not the same as testing whether the predicate is actually the same.

Predicate comparison is perfectly possible. What you are doing wrong is you are using lambda expressions, basically declaring new methods for each predicate (AND for their comparison)! :)
Instead of lambdas, use normal functions.
For example, declare: bool AlbumNameFilter(Album album) {return album.Name == "Winter";}
You will be able to add AlbumNameFilter to Predicates list and Find it later:
Predicates.Contains(AlbumnameFilter);

Switch to
Expression< Func< Album, bool>> list
and create custom comparer

You can use Dictionary instead of List. Then you can compare the different Predicates by whatever you assign as a Key.
Dictionary<(YourKey), Predicate<Album>> predicates = new Dictionary<(YourKey), Predicate<Album>>;
....
if (!predicates.ContainsKey((YourKey)))
{
predicates.Add((YourKey), x => x.AlbumName == "Winter")
}
else
{
predicates.Remove((YourKey));
}
Then to use the Predicate you just access the Dictionary Value.

Related

How does OrderBy extension method orders collection

Suppose we have a class Foo which has an Int32 Field Bar and you want to sort the collection of the Foo objects by the Bar Value. One way is to implement IComparable's CompareTo() method, but it can also be done using Language Integrated Query (LINQ) like this
List<Foo> foos = new List<Foo>();
// assign some values here
var sortedFoos = foos.OrderBy(f => f.Bar);
now in sortedFoos we have foos collection which is sorted. But if you use System.Diagnostics.StopWatch object to measure the time it took OrderBy() to sort the collection is always 0 milliseconds. But whenever you print sortedFoos collection it's obviously sorted. How is that possible. It takes literary no time to sort collection but after method execution the collection is sorted ? Can somebody explain to me how that works ? And also one thing. Suppose after sorting foos collection I added another element to it. now whenever I print out the collection the the element I added should be in the end right ? WRONG ! The foos collection will be sorted like, the element I added was the part of foos collection even if I add that element to foos after sorting. I don't quit understand how any of that work so can anybody make it clear for me ?!
Almost all LINQ methods use lazy evaluation - they don't immediately do anything, but they set up the query to do the right thing when you ask for the data.
OrderBy follows this model too - although it's less lazy than methods like Where and Select. When you ask for the first result from the result of OrderBy, it will read all the data from the source, sort all of it, and then return the first element. Compare this to Select for example, where asking for the first element from the projection only asks for the first element from the source.
If you're interested in how LINQ to Objects works behind the scenes, you might want to read my Edulinq blog series - a complete reimplementation of LINQ to Objects, with a blog post describing each method's behaviour and implementation.
(In my own implementation of OrderBy, I actually only sort lazily - I use a quick sort and sort "just enough" to return the next element. This can make things like largeCollection.OrderBy(...).First() a lot quicker.)
LINQ believe in deferred execution. This means the expression will only be evaluated when you started iterating or accessing the result.
The OrderBy extension uses the deault IComparer for the type it is working on, unless an alternative is passed via the appropriate overload.
The sorting work is defered until the IOrderedEnumerable<T> returned by your statement is first accessed. If you place the Stopwatch around that first access, you'll see how long sorting takes.
This makes a lot of sense, since your statement could be formed from multiple calls that return IOrderedEnumerables. As the ordering calls are chained, they fluently extend the result, allowing the finally returned IOrderedEnumerable to perform the sorting in the most expedient way possible. This is probably achieved by chaining all the IComparer calls and sorting once. A greedy implementation would have to wastefully sort multiple times.
For instance, consider
class MadeUp
{
public int A;
public DateTime B;
public string C;
public Guid D;
}
var verySorted = madeUps.OrderBy(m => m.A)
.ThenBy(m => m.B)
.ThenByDescending(m => m.C)
.ThenBy(m => m.D);
If verySorted was evaluated greedily, then every property in the sequence would be evaluated and the sequence would be reordered 4 times. Because the linq implementation of IOrderedEnumerable deferes sorting until enumeration, it is able to optimise the process.
The IComparers for A, B, C and D can be combined into a composite delegate, something like this simplified representation,
int result
result = comparerA(A, B);
if (result == 0)
{
result = comparerB(A, B);
if (result == 0)
{
result = comparerC(A, B);
if (result == 0)
{
result = comparerD(A, B);
}
}
}
return result;
the composite delegate is then used to sort the sequence once.
You have to add the ToList() to get a new collection. If you do't the OrderBy will be called when you start iterating on sortedFoos.
List<Foo> foos = new List<Foo>();
// assign some values here
var sortedFoos = foos.OrderBy(f => f.Bar).ToList();

Trivial lambdas in LINQ

Edit: Despite the upvotes I don't think this is a good question anymore (see various comments). Sorry for the wasted space, but unfortunately I lack the rep to delete my own post.
Is there a better way of creating a lambda (or perhaps a predicate or expression that is not a lambda) that returns either 1) The sole argument unchanged or 2) a constant value? I encounter this occasionally when using LINQ where a basic LINQ extension method requires a Func<x,y> but I only need the input argument or a constant.
In a two year-old question Jon Skeet asserted that there is no reduction for the identity function (see LINQ identity function?). Is same true of a constant expression? Has (or will) anything chang(ed) with .NET 4.5 or C#5?
you don't need to specify a predicate for the Count method
.Count()
If you were looking for a kind of lambda constant, a regular method would be the closest candidate. Let us say a Func<string,bool> is required and you want it to return it true in any case. Instead of writing collection.SomeLinqMethod(s => true) you could create a static class with appropriate methods
public static class Expressions
{
public static bool True(string s)
{
return true;
}
}
Then you would write
var result = collection.SomeLinqMethod(Expressions.True);
You could also have generic methods
public static bool True<T>(T item)
{
return true;
}

LINQ extension methods - Any() vs. Where() vs. Exists()

Unfortunately the names of these methods make terrible search terms, and I've been unable to find a good resource that explains the difference between these methods--as in when to use each.
Thanks.
Edit:
The sort of query that I'm trying to fully understand is something like this:
context.Authors.Where(a => a.Books.Any(b => b.BookID == bookID)).ToList();
And thanks to all who've answered.
Where returns a new sequence of items matching the predicate.
Any returns a Boolean value; there's a version with a predicate (in which case it returns whether or not any items match) and a version without (in which case it returns whether the query-so-far contains any items).
I'm not sure about Exists - it's not a LINQ standard query operator. If there's a version for the Entity Framework, perhaps it checks for existence based on a key - a sort of specialized form of Any? (There's an Exists method in List<T> which is similar to Any(predicate) but that predates LINQ.)
context.Authors.Where(a => a.Books.Any(b => b.BookID == bookID)).ToList();
a.Books is the list of books by that author. The property is automatically created by Linq-to-Sql, provided you have a foreign-key relationship set up.
So, a.Books.Any(b => b.BookID == bookID) translates to "Do any of the books by this author have an ID of bookID", which makes the complete expression "Who are the authors of the book with id bookID?"
That could also be written something like
from a in context.Authors
join b in context.Books on a.AuthorId equal b.AuthorID
where b.BookID == bookID
select a;
UPDATE:
Any() as far as I know, only returns a bool. Its effective implementation is:
public Any(this IEnumerable<T> coll, Func<T, bool> predicate)
{
foreach(T t in coll)
{
if (predicte(t))
return true;
}
return false;
}
Just so you can find it next time, here is how you search for the enumerable Linq extensions. The methods are static methods of Enumerable, thus Enumerable.Any, Enumerable.Where and Enumerable.Exists.
google.com/search?q=Enumerable.Any
google.com/search?q=Enumerable.Where
google.com/search?q=Enumerable.Exists
As the third returns no usable result, I found that you meant List.Exists, thus:
google.com/search?q=List.Exists
I also recommend hookedonlinq.com as this is has very comprehensive and clear guides, as well clear explanations of the behavior of Linq methods in relation to deferness and lazyness.
Any - boolean function that returns true when any of object in list satisfies condition set in function parameters. For example:
List<string> strings = LoadList();
boolean hasNonEmptyObject = strings.Any(s=>string.IsNullOrEmpty(s));
Where - function that returns list with all objects in list that satisfy condition set in function parameters. For example:
IEnumerable<string> nonEmptyStrings = strings.Where(s=> !string.IsNullOrEmpty(s));
Exists - basically the same as any but it's not generic - it's defined in List class, while Any is defined on IEnumerable interface.
Any() returns true if any of the elements in a collection meet your predicate's criteria. (Any() does not iterate through the entire collection, as it returns upon the first match.)
Where() returns an enumerable of all elements in a collection that meet your predicate's criteria.
Exists() does the same thing as Any() except it's just an older implementation that was there on the List back before LINQ.
IEnumerable introduces quite a number of extensions to it which helps you to pass your own delegate and invoking the resultant from the IEnumerable back. Most of them are by nature of type Func
The Func takes an argument T and returns TResult.
In case of
Where - Func : So it takes IEnumerable of T and Returns a bool. The where will ultimately returns the IEnumerable of T's for which Func returns true.
So if you have 1,5,3,6,7 as IEnumerable and you write .where(r => r<5) it will return a new IEnumerable of 1,3.
Any - Func basically is similar in signature but returns true only when any of the criteria returns true for the IEnumerable. In our case, it will return true as there are few elements present with r<5.
Exists - Predicate on the other hand will return true only when any one of the predicate returns true.
So in our case if you pass .Exists(r => 5) will return true as 5 is an element present in IEnumerable.
foreach (var item in model.Where(x => !model2.Any(y => y.ID == x.ID)).ToList())
{
enter code here
}
same work you also can do with Contains
secondly Where is give you new list of values.
thirdly using Exist is not a good practice, you can achieve your target from Any and contains like
EmployeeDetail _E = Db.EmployeeDetails.where(x=>x.Id==1).FirstOrDefault();
Hope this will clear your confusion.

Determine if object is any Predicate<T>

I've got an IList<Delegate> that contains some Func<bool>s and some Predicate<T>s, where T varies. I later need to sort out which of these items are Predicate<T>s, but don't want to close the door to adding other Delegate types to the list later, so I do not want to do this by identifying objects by !(current_delegate is Func<bool>).
The highest abstraction below Predicate<T> is MulticastDelegate, which seems unhelpful (would need a non-generic Predicate type under Predicate<T>), and identifying the presence of the generic parameter is also useless given the other generic Delegates that may be present in the list.
The only other thing I've considered is checking the Name of the Type. To me, string comparison is a near-smell, but maybe that is the is the best and/or only way -- you tell me.
What is the best way to definitively determine that an object is any Predicate<T> without knowing the type of T?
Like this:
obj.GetType().GetGenericTypeDefinition() == typeof(Predicate<>)
Predicate<int> pred = ...;
var isPreidcate = pred.GetType().GetGenericTypeDefinition() == typeof(Predicate<>);
On another note, if you have a generic list, you shoulnd't need to check the types in it. You may want to rethink your design if you need to check for specific types within a list.
You can have a list of special classes which wrap your delegates and provide additional sorting information. So you'll indirectly solve the problem.
This should work well enough:
public static bool IsPredicate(object obj) {
var ty = obj.GetType();
var invoke = ty.GetMethod("Invoke");
return invoke != null && invoke.ReturnType == typeof(bool);
}
The trick will be when you actually want to call the function, you will need to use reflection.
Here are some tests:
Func<bool> is pred? True
Func<int, bool> is pred? True
Predicate<int> is pred? True
Func<int> is pred? False

lambda expressions on populated lists

There are a few posts on the site about how to order by using lambda expressions however I cannot seem to get mine to work. I am trying to reorder a list that is already populated. Am i wrong in thinking that i can rearrange the order of this list using lambada expressions?
QuarterMileTimes.OrderByDescending(c => c.PquartermileTime);
I was wondering if it's down to PquartermileTime being a string? I also tried this expression on a date
QuarterMileTimes.orderBy(c => c.RaceDay);
Still no luck where am I going wrong?
When you call OrderByDescending, the method returns a new IEnumerable<T> - it does not reorder the collection in place.
Try doing:
QuarterMileTimes = QuarterMileTimes.OrderByDescending(c => c.PquartermileTime).ToList();
(This is if your collection is a List<T>...)
The result of OrderByDescending (and all of the other Enumerable extension methods) is an IEnumerable<T> that projects the source data in the order you're describing. It does not alter the original data in any way.
If you prefer, you can use the ToList() extension method to create a new List<T> from that result and assign it back to the original variable.
QuarterMileTimes = QuarterMileTimes.OrderByDescending(/*...*/).ToList();
(This is assuming, of course, that QuarterMileTimes is a List<T>)
The gist of the answer is no, OrderByDescending does not alter the data source in any way.
You are assigning it to a new variable aren't you?
var sortedTimes = QuarterMileTimes.OrderByDescending(c => c.PquartermileTime);
It isn't like e.g. the List.Sort method, that sorts the existing list.
The result of the method has to be assigned to a variable.
OrderByDescending returns an IOrderedEnumerable<T> i.e. a new sequence with the items in the specified order. You'll have to re-assign QuarterMileTimes to get the behaviour you expect:
QuarterMileTimes = QuarterMileTimes.OrderByDescending(c => c.PquarterMileTime).ToList();
Alternatively you can just use the returned sequence separately, which is the usual approach.
QuarterMileTimes.OrderByDescending(c => c.PquartermileTime) returns a new enumerable, ordered by PquartermileTime. It does not reorder QuarterMileTimes in place.

Categories