'Find Max/Min element without using IComparable<T>
Say I have the following:
public Class BooClass
{
public int field1;
public double field2;
public DateTime field3;
}
public List<BooClass> booList;
So for example how do I get the element with the earliest time in field3 using booList.Find()
Edit Apologies, I meant to make all the fields public for simplicity of the example. I know can do it in linq, I wondered if there is a simple single line condition for the Find method.
Solution 1:[1]
You'll need to expose field3 through through a public property (we'll call it Field3), but you could use this:
var earliest = booList.First(b => b.Field3 == booList.Min(e => e.Field3));
Take a look at Enumerable.First and Enumerable.Min
NOTE: That this has a time complexity of O(n^2) (quadratic time) because it is traversing the list via Min each iteration. A large enough collection will see serious performance issues compared to Saeed Amiri's answer, which runs in O(n) (linear time).
Solution 2:[2]
Use OrderBy Then get the first element
var result = booList.OrderBy(p => p.field3).FirstOrDefault();
Solution 3:[3]
The O(n) approach is as follows. First find min date (for field3), then find first object with this min date:
var minDate = booList.Min(x=>x.field3);
var item = booList.First(x=>x.field3 == minDate);
Just make your property public.
Solution 4:[4]
As far as I can tell, there is no way to retrieve the BooClass object with the minimal date by just using List<T>.Find. Of course you can do this:
void Main()
{
List<BooClass> booList = new List<BooClass> {
new BooClass { field3 = DateTime.MaxValue},
new BooClass { field3 = DateTime.Now },
new BooClass { field3 = DateTime.MinValue }};
var pred = GetPredicate(booList);
var result = booList.Find(pred);
}
public Predicate<BooClass> GetPredicate(List<BooClass> boos)
{
var minDate = boos.Min(boo => boo.field3);
return bc => bc.field3 == minDate;
}
(which - just like Saeed's solution - also has O(n) time complexity), but I guess that would be considered cheating...
Solution 5:[5]
If you don't want to define a MinBy method, you can use aggregate like so:
booList.Aggregate((currMin, test) => currMin < test ? currMin : test);
To support empty lists, seed the aggregate with null, like so:
booList.Aggregate(null, (currMin, test) => null == currMin || currMin > test ? test : currMin);
This solution is O(n)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Community |
| Solution 2 | shenhengbin |
| Solution 3 | Gupta |
| Solution 4 | afrischke |
| Solution 5 |
