This question already has answers here:
What is a Predicate Delegate and where should it be used?
(10 answers)
Closed 8 years ago.
I am very new to using predicates and just learned how to write:
Predicate<int> pre = delegate(int a){ a %2 == 0 };
What will the predicate return, and how is it useful when programming?
Predicate<T> is a functional construct providing a convenient way of basically testing if something is true of a given T object.
For example suppose I have a class:
class Person {
public string Name { get; set; }
public int Age { get; set; }
}
Now let's say I have a List<Person> people and I want to know if there's anyone named Oscar in the list.
Without using a Predicate<Person> (or Linq, or any of that fancy stuff), I could always accomplish this by doing the following:
Person oscar = null;
foreach (Person person in people) {
if (person.Name == "Oscar") {
oscar = person;
break;
}
}
if (oscar != null) {
// Oscar exists!
}
This is fine, but then let's say I want to check if there's a person named "Ruth"? Or a person whose age is 17?
Using a Predicate<Person>, I can find these things using a LOT less code:
Predicate<Person> oscarFinder = (Person p) => { return p.Name == "Oscar"; };
Predicate<Person> ruthFinder = (Person p) => { return p.Name == "Ruth"; };
Predicate<Person> seventeenYearOldFinder = (Person p) => { return p.Age == 17; };
Person oscar = people.Find(oscarFinder);
Person ruth = people.Find(ruthFinder);
Person seventeenYearOld = people.Find(seventeenYearOldFinder);
Notice I said a lot less code, not a lot faster. A common misconception developers have is that if something takes one line, it must perform better than something that takes ten lines. But behind the scenes, the Find method, which takes a Predicate<T>, is just enumerating after all. The same is true for a lot of Linq's functionality.
So let's take a look at the specific code in your question:
Predicate<int> pre = delegate(int a){ return a % 2 == 0; };
Here we have a Predicate<int> pre that takes an int a and returns a % 2 == 0. This is essentially testing for an even number. What that means is:
pre(1) == false;
pre(2) == true;
And so on. This also means, if you have a List<int> ints and you want to find the first even number, you can just do this:
int firstEven = ints.Find(pre);
Of course, as with any other type that you can use in code, it's a good idea to give your variables descriptive names; so I would advise changing the above pre to something like evenFinder or isEven -- something along those lines. Then the above code is a lot clearer:
int firstEven = ints.Find(evenFinder);
The Predicate will always return a boolean, by definition.
Predicate<T> is basically identical to Func<T,bool>.
Predicates are very useful in programming. They are often used to allow you to provide logic at runtime, that can be as simple or as complicated as necessary.
For example, WPF uses a Predicate<T> as input for Filtering of a ListView's ICollectionView. This lets you write logic that can return a boolean determining whether a specific element should be included in the final view. The logic can be very simple (just return a boolean on the object) or very complex, all up to you.
The following code can help you to understand some real world use of predicates (Combined with named iterators).
namespace Predicate
{
class Person
{
public int Age { get; set; }
}
class Program
{
static void Main(string[] args)
{
foreach (Person person in OlderThan(18))
{
Console.WriteLine(person.Age);
}
}
static IEnumerable<Person> OlderThan(int age)
{
Predicate<Person> isOld = x => x.Age > age;
Person[] persons = { new Person { Age = 10 }, new Person { Age = 20 }, new Person { Age = 19 } };
foreach (Person person in persons)
if (isOld(person)) yield return person;
}
}
}
In C# Predicates are simply delegates that return booleans. They're useful (in my experience) when you're searching through a collection of objects and want something specific.
I've recently run into them in using 3rd party web controls (like treeviews) so when I need to find a node within a tree, I use the .Find() method and pass a predicate that will return the specific node I'm looking for. In your example, if 'a' mod 2 is 0, the delegate will return true. Granted, when I'm looking for a node in a treeview, I compare it's name, text and value properties for a match. When the delegate finds a match, it returns the specific node I was looking for.
Related
I am calling an employee search API provided by a third party which returns me a list of employees as a search result. This Employee class has N number of properties (for example, FirstName, LastName, Address, Mobile No and many others). I want to compare the "FirstName" property of these search results with the search text. If it matches, I want these matching results sorted at the top of the collection. So far, I have tried using IComparer and IComparable but they both are not suitable for my requirement. Sharing an example of my requirement below :
Example: I searched for "John" in API and API gave me 10 results. Out of these 10 results, only 1 had john as a first name, and the rest 9 of them have john in other properties. I want an employee with FirstName "John" as the first result.
You can sort your list via
var sorted = resultFromApi.OrderByDescending(x => x.FirstName == "John").ToList();
Your new list will have all items where FirstName is "John" in the beginning, and all items where FirstName has another value in the end.
I have tried using IComparer and IComparable but they both are not suitable for my requirement.
You can definitely leverage IComparer for this:
public class BumpToFirstComparer : IComparer<string>
{
private readonly string valueToBump;
public BumpToFirstComparer(string valueToBump)
{
this.valueToBump = valueToBump;
}
int IComparer<string>.Compare(string? x, string? y)
{
if (x == this.valueToBump) return -1;
if (y == this.valueToBump) return 1;
return 0;
}
}
Notice how we say that "every element is identical, with the exception of this special case that I want to handle: if the special case is found as the first in the comparison, we always say it should come before the second, and if it is found as the second, then the second always comes first.
You can then just pass this into any ascending sorting method and it should give you the results you want:
IEnumerable<string> GetInput()
{
yield return "Juliano";
yield return "SomeoneElse";
yield return "John";
yield return "YetAnotherPerson";
}
foreach (var ordered in GetInput().Order(new BumpToFirstComparer("John")))
{
Console.WriteLine(ordered);
}
This produces:
John
Juliano
SomeoneElse
YetAnotherPerson
John is now at the top, while the rest of the list remains intact.
I need to compare two objects of the same type but with a lot of prop
return string.Equals(x.Name, y.Name) &&
x.Price == y.Price &&
string.Equals(x.Species, y.Species) &&
x.AgeEnforced == y.AgeEnforced &&
x.MinimumAge == y.MinimumAge &&
string.Equals(x.WeightRange, y.WeightRange) &&
x.MinimumWeight == y.MinimumWeight
The list goes on up to 14 props
A hint on how can I lose && operator?
If your class has 14 properties and all of them have to be compared to ensure equality, all of these checks have to be made somewhere. No matter if you put them into a (maybe static) helper method, the Equals-method, a class that implements IEqualityComparer (IMHO the best choice), an extension method or whatever else comes to your mind, you have to write down all of these checks once.
Instead of writing these checks on yourself you can use some reflection stuff (or a library that makes use of it) by iterating over all properties, but that's normally not the best choice, cause it is slower and equality checks are tend to be called very often (sort, hashset, etc.). So take the pain and write the checks down.
If you think these are too many checks, then maybe your object is to fat and has to much properties. Maybe it needs a deeper hierarchy by using classes which are representing a part of the whole thing and you have a top class that has as property a child class and then you write the compare method for each child class individually and the top class just calls these comparers for its child classes.
Answer to A hint on how can i lose && operator?
if (string.Equals(x.Name, y.Name) == false) return false;
if (x.Price != y.Price) return false
// ... others
return true;
This code must be somewhere. If this is only place where this code exist this is ok in my opinion. Bu if it exists in many places then you can move it to some helper fuction or override Equals() method in your object. MSDN info.
Example how to oveeride and use Equals():
public class MyObject
{
public string Name { get; set; }
public decimal Price { get; set; }
public override bool Equals(object obj)
{
MyObject o = obj as MyObject;
if (o == null)
return false;
if (this.Name != o.Name)
return false;
return true;
}
/// <summary>
/// Serves as the default hash function.
/// </summary>
/// <returns>
/// A hash code for the current object.
/// </returns>
public override int GetHashCode()
{
return base.GetHashCode();
}
}
public class Program
{
static public void Main()
{
MyObject o1 = new MyObject()
{
Name = "a",
Price = 1
};
MyObject o2 = new MyObject()
{
Name = "b",
Price = 1
};
MyObject o3 = new MyObject()
{
Name = "a",
Price = 1
};
Console.WriteLine("o1 == o2: {0}", o1.Equals(o2));
Console.WriteLine("o1 == o3: {0}", o1.Equals(o3));
Console.ReadKey();
}
}
Result is:
o1 == o2: False
o1 == o3: True
For me, && or || are pretty short already. Your problem lies not in the operator itself, but in the way you are doing the comparison of 14+ properties.
Instead of writing all the property-comparisons by hand, you can try automating it.
var props_string = new List<Func<MyObject, string>>();
props_string.Add(foo => foo.Name);
props_string.Add(foo => foo.Species);
//..
var props_double = new List<Func<MyObject, double>>();
props_double.Add(foo => foo.Price);
//..
Now, having them listed, you can ran a loop over it
MyObject first = ...;
MyObject second = ...;
bool areEqual = true;
foreach(var prop in props_string)
if(!string.Equals(prop(first), prop(second)))
areEqual = false;
foreach(var prop in props_double)
if(prop(first) != prop(second))
areEqual = false;
return areEqual;
The positive side is that even if there were 100 properties, one or two (or more) loops would fly over it.
Please note that this code is not optimized and pretty naive.
More natural would be a fast-exit on first difference:
foreach(var prop in props_double)
if(prop(first) != prop(second))
return false;
..and/or observing that string.equals and double!=double can all be packed as the same object.Equals method (so you don't need separate props_string, props_double etc)
..and/or observing that you don't really need to list all properties, you can get them from Reflection, so you don't need to 'define' the 100 properties in these lists. (But then, you often have some special properties that you don't want to include.. so your reflection-way would need a way to detect and skip them..)
..and/or observing that if you used struct instead of class you would get full memberwise object.Equals comparison for free. (But then, structs differ from classes in many other things..)
..and/or(...)
All these 'optimizations' are highly dependent on what you have in the rest of the 14+ comparisons. It looks fun and smart at first, but the more the types of properties vary and the more types of comparisons you need to do (string.equals with case-insensitive maybe?) the worse it will get. Sometimes 14 times &&, or 14 times if(x==y)return false isn't really that bad.
Please don't get me wrong: I do not advise you to use the way I show here. I just show you that it is possible. Don't use it unless absolutely relevant and necessary. Doing it this way may cost you much more time than you would want to.
This seems as a correct way how to do the compare.
If your aim is to be able to easily check if two different instances are equal you can override Equals() and GetHashCode().
You will be able to do:
x.Equals(y)
You can also override operator ==. In which case you can do:
x == y
Check MSDN for details and example.
Also there is no reason for you (unless you want to use any extra parameters) to use
string.Equals(x.Name, y.Name)
use simply
x.Name == y.Name
How can one go about sharing query logic between LINQ and Rx? i.e., if I need to sometimes query against an IObservable stream and sometimes against an IEnumerable, but the exact same logic is in each, is there any way to share that logic?
Maybe an example will help. In the following Queries class, I want to combine the sequence of people and purchases to produce a "notice" string. Notice I have to duplicate the exact same logic; all that's different is that one is IEnumerable and one is IObservable. Is there any way of consolidating these two functions? I've tried using various combinations of ToObservable and ToEnumerable, but everything I've tried seems to either hang or produce no result.
(Higher-kinded question: Is this the exact thing that the idea of higher-kinded types was created to solve? i.e., would this not even be a problem in Haskell or Scala?)
static class Queries {
static IObservable<string> GetPurchaseNotices(IObservable<Person> people, IObservable<Purchase> purchases) {
return from person in people
from purchase in purchases
where person.Id == purchase.PurchaserId
select person.Name + " purchased a " + purchase.ItemName;
}
static IEnumerable<string> GetPurchaseNotices(IEnumerable<Person> people, IEnumerable<Purchase> purchases) {
return from person in people
from purchase in purchases
where person.Id == purchase.PurchaserId
select person.Name + " purchased a " + purchase.ItemName;
}
}
class Person {
public Person(int id, string name) {
Id = id;
Name = name;
}
public string Name;
public int Id;
}
class Purchase {
public Purchase(int purchaserId, string itemName) {
PurchaserId = purchaserId;
ItemName = itemName;
}
public int PurchaserId;
public string ItemName;
}
As far as I know, this is not possible in C# (or F#) directly. The problem is that while you can abstract over the generic argument T in IEnumerable<T> or IObservable<T>, you cannot abstract over the "kind" IEnumerable or IObservable.
With higher-kinded types, like those in Haskell or Scala, you could express this given a suitable interface for IEnumerble and IObservable. In Haskell, it would look something like:
getPurchases :: MonadPlus m => m Person -> m Purchaser -> m String
getPurchases people purchases = do
person <- people
purchase <- purchases
if (personId person) == (purchaserId purchase)
then return $ (name person) ++ "purchased a " ++ (itemName purchase)
else mzero
which you could then use for both IEnumerable and IObservable.
I don't know whether IObservable actually satisfies the required laws for MonadPlus however, so this is just an example.
Switching from observable to enumerable is not a good idea since the enumerable will block, so it will be less problematic the other way around. You should be able to use a single function that filters an IObservable<Person>.
Here's simple program that demonstrates the idea. Notice it uses a single method for filtering IObservable<int>. In case of IEnumerable<int>, it switches ToObservable before calling the method, and then switches back ToEnumerable after getting the result.
static void Main(string[] args)
{
var observableNums = Observable.Interval(TimeSpan.FromSeconds(1))
.Select(x => (int)x);
var observableOdds = FilterOdds(observableNums);
observableOdds.Subscribe(Console.WriteLine);
var enumerableNums = new[] { 1, 2, 3, 4, 5, 6 };
var enumerableOdds = FilterOdds(enumerableNums.ToObservable());
foreach (var i in enumerableOdds.ToEnumerable())
Console.WriteLine(i);
Console.ReadKey();
}
static IObservable<int> FilterOdds(IObservable<int> nums)
{
return nums.Where(i => i % 2 == 1);
}
Ive got the following query that binds to a DropDownList;
if (!Page.IsPostBack)
{
var branchTags =
(
from t in context.ContactSet
orderby t.py3_BranchArea
where t.py3_BranchArea != null
select new
{
BranchTagCode = t.py3_BranchArea,
BranchTag = (t.FormattedValues != null && t.FormattedValues.Contains("py3_brancharea") ? t.FormattedValues["py3_brancharea"] : null)
}
).Distinct();
ddlBranchTags.DataSource = branchTags;
ddlBranchTags.DataBind();
}
For some reason it still ourputs 2 rows that are visually the same. It might be the case that there are two enitites in the CRM with the same name. But, if Im using distinct on the query and only returning the 'py3_brancharea' then surely the Distinct should be run on the actual records returned?
So, this suggests to me -and my limited LINQ knowledge- that its because of the line:
BranchTagCode = t.py3_BranchArea
But, this needs to be called to make it possible to call the FormattedValues.
How then do I get a distinct set of results based purely on 'BranchTag' ?
If Distinct() is not working it is possibly a problem with the particular classes gethashcode() or equals() override methods, which are either not set up correctly or omitted entirely. In a custom class you will most likely need to specify these overrides to get Distinct() and other like methods to function correctly.
You could try to use a where or any clause to differentiate between duplicates as well. Which could be a work around for the Distinct() issues.
To further explain how to set up the Distinct() Method with custom classes. You will need to within the class that you are searching through set the override methods GetHashCode() and Equals(). These or Object level methods that should be in every single class no matter what. To start head to the class in question and type this:
public override bool Equals(object obj)
then
public override int GetHashCode()
Lets say you have this simple class before the overrides:
class foo{
int H {get;set;}
public foo(int _h){
H = _h;
}
}
It would now look like this:
class foo{
int H {get;set;}
int K {get;set;}
public override bool Equals(object obj){
if(obj == null) return false;
foo test = (foo)obj);
if(test == null) return false;
if(this.H == obj.H && this.K == obj.K) return true;
}
public override int GetHashCode(){
int hashH = H.GetHashCode();
int hashK = K.GetHashCode();
return hashH ^ hashK;
}
public foo(int _h){
H = _h;
}
}
Now you could use Distinct() on Ienumerable types containing the foo class like so:
List<foo> FooList = new List<foo>(Collection of 9 Foos);
var res = FooList.Distinct();
Another, much more simple way that worked for me, but may not work in all situations, is using this guys method ( GroupBy() and First()):
Finding Distinct Elements in a List
He creates a List<Customer> customers with FirstName and LastName. Then groups them all by FirstName and grabs the first element from each group!
`
List< Customer > customers = new List< Customer >;
{
new Customer {FirstName = "John", LastName = "Doe"},
new Customer {FirstName = "Jane", LastName = "Doe"},
new Customer {FirstName = "John", LastName = "Doe"},
new Customer {FirstName = "Jay", LastName = null},
new Customer {FirstName = "Jay", LastName = "Doe"}
};
`
Then:
`
var distinctCustomers = customers.GroupBy(s => s.FirstName)
.Select(s => s.First());
`
In my situation, I had to use FirstOrDefault() though.
Is it possible that the two results are different, do they have the same branch tag code and branch tag?
You could implement a custom equality comparer and pass it to distinct() so that it only compares the field that you want? it's a bit more difficult because of the anonymous type in your select statement, but this answer has a way around that.
The default equality comparison for anonymous types is case sensitive. Do the returned values you expect have different casing? As Matt suggested you may want to look at a custom IEqualityComparer implementation on a custom class otherwise.
I changed my code from
.Distinct().ToList();
to
.ToList().Distinct().ToList();
and now it's able to avoid the duplicate. Not sure what's the reason behind.
Another possibility it that the Entity Object has a define key that is not unique.
I'm using NUnit 2.5.7. I want to test whether a collection of custom objects of a particular class contains certain objects, based on one of the class's properties.
e.g. a contrived example...
public class Person
{
public string Name { get; set; }
public Person(string name)
{
Name = name;
}
}
// ...
public List<Person> GetFavouritePeople()
{
List<Person> favouritePeople = new List<Person>();
favouritePeople.Add(new Person("joe"));
favouritePeople.Add(new Person("fred"));
favouritePeople.Add(new Person("jenny"));
return favouritePeople;
}
// ...
[Test]
public GetFavouritePeople()
{
List<Person> people = GetFavouritePeople();
// What I'd like to test, but not sure how to do it...
Assert.Contains(Name="joe", people);
Assert.Contains(Name="fred", people);
Assert.Contains(Name="jenny", people);
}
Although it would be simple enough in this example, I don't want to create mock objects for each Person and use those in the assertion... I just want to check based on a particular property (Name in this example.)
You could use LINQ:
Assert.That(people.Any(p => p.Name == "joe"));
or, if you want to be explicit about there being exactly one person with each name:
Assert.That(people.Count(p => p.Name == "joe"), Is.EqualTo(1));
If you want a better error message than "Assertion failed, expected true, was false", you could create your own assert method.
For several collection-related asserts, CollectionAssert is very useful - for instance, it allows you to check if two collections contain the same elements, irrespective of their order. So yet another possibility is:
CollectionAssert.AreEquivalent(new[] {"joe", "fred", "jenny"}, people.Select(p => p.Name).ToList());
Note that CollectionAssert.AreEquivalent() is a little picky with regard to the types it accepts (even though the signature takes IEnumerable). I usually wrap it in another method that calls ToList() on both parameters before invoking CollectionAssert.AreEquivalent().
You can use Assert.That in conjunction with Has.Exactly(1).Matches:
List<Person> people = GetFavouritePeople()
Assert.That(people, Has.Exactly(1).Matches<Person>(p => p.Name == "NUnit is amazing")));
Failure message will be along lines of:
Expected: exactly one item value matching lambda expression
But was: 0 items < [result of people.ToString()] >
You can use Linq's Intersect() to determine whether all the expected items are within the list your testing against even if the list contains other items that you are not testing for:
[Test]
public void TestFavouritePeople()
{
var people = GetFavouritePeople();
var names = people.Select(p => p.Name);
var expectedNames = new[] {"joe", "fred", "jenny"};
var actualNames = names.Intersect(expectedNames);
CollectionAssert.AreEquivalent(expectedNames, actualNames);
}
For NUnit 3.0 and greater, you can use Is.SupersetOf():
[Test]
public void TestFavouritePeople()
{
var people = GetFavouritePeople();
var names = people.Select(p => p.Name);
var expectedNames = new[] {"joe", "fred", "jienny"};
var actualNames = names;
Assert.That(actualNames, Is.SupersetOf(expectedNames));
}