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.
Related
Let's say I have a List of Songs.
Song {
public string Name = "";
public int PlayOrder = 0;
}
Now I want to sort them first by PlayOrder starting at zero and second by Name alphabetically.
So an example set of sorted results would be (Name, PlayOrder):
/*
Pachelbel's Canon, 0
A Happy Song, 4
Beethoven's 5th, 4
Some Other Song, 7
*/
See how the PlayOrder = 4 ones are in order alphabetically? That's what I'm going for.
Right now I have it only sorting by one field:
List<Song> final = new List<Song>();
...
final.Sort((x, y) => x.PlayOrder.CompareTo(y.PlayOrder));
return final;
How can I also sort by Name as demonstrated above?
return final.OrderBy(s => s.PlayOrder).ThenBy(s => s.Name);
If you want to continue using the sort method you will need to make your comparison function smarter:
final.Sort((x, y) => {
var ret = x.PlayOrder.CompareTo(y.PlayOrder);
if (ret == 0) ret = x.Name.CompareTo(y.Name);
return ret;
});
If you want to use LINQ then you can go with what K Ivanov posted.
If you only have one preferred way of sorting your Song class, you should implement IComparable and/or IComparable<Song>:
List<Song> songs = GetSongs();
songs.Sort(); // Sorts the current list with the Comparable logic
If you have multiple ways how you want to store your list, IEqualityComparer<T> is the interface you would like to implement. Then you can provide that comparer as argument in List<T>Sort().
I'm having some problems retrieving information from a list.
In this case I'd like to get the name from a list, eventually I want it turned into a string. This is what I have:
public string ShowName(int patientcode)
{
List<ExtendPatientInfo> patientdata = dk.RetrieveList(patientcode);
string name = patientdata. <What here?>
return name;
}
In the class ExtendPatientInfo I have this, which I think is allright:
private string name;
public ExtendPatientInfo(string name)
{
this.name = name;
}
public string Name
{
get
{
return name;
}
}
I tried using a few things. Like Contains, Find, FindIndex and where. But none of these worked for me because I probably messed something up somewhere. Anybody that can help me?
You have to choose the patient. If it is all the same data for the patient, then you can use LINQ's First
patientdata.First().Name
But, if they are all different, then you could map the list to only have Names
patientdata.Select(x=>x.Name)
At which point, you would still need to iterate through the list to display each name or whatever you need.
As Henk points out, if this is always going to be a list of one item, then you could use
patientdata.Single().Name
*The caveat with Single is from MSDN
Returns the only element of a sequence, and throws an exception if there is not exactly one element in the sequence.
Well you have a list of object and you want to show properties of each object, then you have to access each object in the list and then access it properties. Something like:
foreach(var item in patientdata)
{
Console.WriteLine(item.Name);
//rest of the fields
}
If you want to select a single object from your list then you cause use First / FirstOrDefault , Single / SingleOrDefault depending on your need. But you need an individual object to access it properties. You can't access a property directly from a list.
var item = patientData.FirstOrDefault();
if(item != null)
Console.WriteLine(item.Name);
Try
string name = string.Empty;
var pd = patientData.FirstOrDefault();
if(pd != null)
name = pd.Name
This code gets the first item returned or null.
If it isn;t null it retrieves the Name property value into string variable name.
Incidentally, if you don;t want to learn linq right now you can access List<> via index like:
patientData[0].Name
You will still want to check that patientData[0] is not null before checking the Name property.
You probably want to use Linq. Linq allows you to cycle through a list easily and get what you want.
For example, if you want the patient named "Johan":
ExtendPatientInfo patient = patientdata.Where(x => x.Name == "Johan").FirstOrDefault();
string name = patient.Name;
If I understand your question, you are looking for something like this
ExtendPatientInfo patient =
patientdata.FirstOrDefault(x => x.patientcode == patientcode);
return
(patient != null)
? patient.Name
: null
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);
}
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.
I am curious on how the following code works, especially the part the contains the delegate stuff since I am new to it. Also, are there any bottlenecks in the code, for example, would using a SortedDictionary be better than using a List and then sorting it using LINQ? Ok, here is the code:
public class ColorManager
{
private List<ColorData> colorCodes = new List<ColorData>();
public List<ColorData> ColorCodes
{
get
{
var sortList = from a in this.colorCodes
orderby a.colorCode ascending
select a;
return sortList.ToList();
}
}
public void FillData(DataTable table)
{
for(int row = 0; row < table.Rows.Count; row++)
{
ColorData cData = new ColorData();
string name = table.Rows[row]["Color"].ToString().Trim();
if(!this.colorCodes.Exists(
delegate(ColorData e)
{
return e.ColorCode == name;
}))
{
cData.Add(table.Rows[row]["Color"].ToString());
this.colorCodes.Add(cData);
}
else
{
this.colorCodes.Find(
delegate(ColorData e)
{
return e.ColorCode == name;
}).Count++;
}
}
}
}
I am curious on how the following code works, especially the part the contains the delegate stuff since I am new to it.
First take a look at this ColorCodes property accessor:
var sortList = from a in this.colorCodes
orderby a.colorCode ascending
select a;
It returns a list of all the color codes (this.colorCodes) in ascending order (...orderby a.colorCode ascending). Simple so far. How about the meatier FillData method?
First, we'll loop over every row in this table:
for(int row = 0; row < table.Rows.Count; row++)
{
Then, we're going to look at the Color column of the current row.
ColorData cData = new ColorData();
string name = table.Rows[row]["Color"].ToString().Trim();
If that column has no match in our list of color codes, this if condition is true. The Exists method takes a single-argument function that returns a bool, which is what this anonymous delegate is: a single-argument (ColorData e) function that returns a boolean (e.ColorCode == name). It gets negated (!this.[...]), so if a match is found, the condition is false.
if(!this.colorCodes.Exists(
delegate(ColorData e)
{
return e.ColorCode == name;
}))
{
cData.Add(table.Rows[row]["Color"].ToString());
this.colorCodes.Add(cData);
}
Otherwise, if there's a match, find the name using another anonymous delegate, and add one to the count of items of that color.
else
{
this.colorCodes.Find(
delegate(ColorData e)
{
return e.ColorCode == name;
}).Count++;
}
}
Note that this code is somewhat inefficient, since the two different anonymous delegates really do the same thing and could be shared.
Actually, there are more delegates there than you expect. The LINQ query:
var sortList = from a in this.colorCodes
orderby a.colorCode ascending
select a;
is actually:
var sortList = this.colorCodes.OrderBy(a => a.colorCode);
which (for LINQ-to-Objects) is the same as:
var sortList = this.colorCodes.OrderBy(delegate (ColorData a) {
return a.colorCode;
})
This uses a delegate to identify the item to sort by - i.e. "given a ColorData, I'll give you the colorCode". Note that many select uses also involve a delegate, but not in this case (the trivial select a is removed by the compiler).
In the code:
if(!this.colorCodes.Exists(
delegate(ColorData e)
{
return e.ColorCode == name;
}))
we are using a predicate; "given a ColorData, I'll tell you whether it is a match, by testing the name for equality". Note that name here is "captured" into the delegate, which involves some fairly complex compiler tricks (I won't describe them).
Re efficiencies; it is hard to be sure, but perhaps:
Dictionary<string, ColorData> items = new Dictionary<string, ColorData>();
foreach(DataRow row in table.Rows) {
string name = row["Color"].ToString().Trim();
ColorData cData;
if (items.TryGetValue(name, out cData)) {
cData.Count++;
} else {
cData.Add(name);
colorCodes.Add(cData);
items.Add(name, cData);
}
}
This avoids lots of duplication, and uses a dictionary to find values rather than constantly using Contains/Find. In many cases, a LINQ GroupBy might have helped, but not in this case, perhaps.
Its an anonymous delegate that serves as the selection criteria for the find expression. In words, if the color is equal to the color given by name, it will return true and Find will add this to the IEnumerable that it is generating. If it returns false, Find will not contain it. It can be written more succinctly as
p => p.ColorCode == name
Exists and Find are generic extension methods. They for for each loop over each item in the collection. Passing the delegate a parameter (defined like "(ColorData e)"), and returning a boolean.
Delegates:
The delegates in this example are implementing a Func method. Basically, what you're doing, is creating a method on the fly that takes a ColorData argument, and returns a bool.
This lets you do your Exists() and Find() calls on every member of your IEnumerable collection for checking and filtering.
As for Sorted Dictionary:
If this is the only place you're using it, you'd be better off using SortedDictionary, since you wouldn't be resorting it constantly. Right now, every time you call ColorCodes you're resorting. A SortedDictionary would be constantly sorted.