I have a list where each element contains two values (V1 and V2). What I need is the element with the highest V1 and highest V2 (prioritizing V1).
I have tried two approaches:
OrderByDescending and ThenByDescending, then take the first element:
list.OrderByDescending(e => e.V1).ThenByDescending(e => e.V2).First();
Select elements with biggest V1, then select the first element with the biggest V2 from this enumerable:
var maxV1 = l.Where(e => e.V1 == l.Max(e => e.V1));
maxV1.First(e => e.V2 == maxV1.Max(e1 => e1.V2));
Both (in my use case) require a fair amount of time and I'm not satisfied with either of my solutions.
The list itself doesn't contain a lot of elements, not more than 100. But there are a lot of them.
Is there another, preferably more efficient, solution than what I've already tried? Or do I have to rethink the whole architecture?
Edit: I forgot to mention that there are more variables in each element which might be used to select the highest value. Which one is used depends on a parameter. So pre sorting using sorted collections doesn't net any benefits.
You can use GroupBy, then order this V1-group by V2:
var highestItemByV1V2 = list.GroupBy(x => x.V1)
.OrderByDescending(g => g.Key)
.Select(g => g.OrderByDescending(x => x.V2).First())
.First();
You should also store the max value instead of using it as expression in the query, otherwise it will be evaulated always. So this is more efficient:
var highestV1 = list.Max(x => x.V1);
var maxObj = list.Where(x => x.V1 == highestV1).OrderByDescending(x => x.V2).First();
However, your first approach should perform well, it's simple and efficient:
list.OrderByDescending(e => e.V1).ThenByDescending(e => e.V2).First();
So what kind of performance issue do you have? Maybe you are loooking at the wrong place or you call this code too often. Consider to store them already sorted, f.e. in a SortedList. I think that a SortedDictionary is even more efficient in this case.
The SortedDictionary<TKey, TValue> generic class is a binary search
tree with O(log n) retrieval, where n is the number of elements in the
dictionary. In this respect, it is similar to the SortedList<TKey,
TValue> generic class. The two classes have similar object models,
and both have O(log n) retrieval. Where the two classes differ is in
memory use and speed of insertion and removal:
SortedList<TKey, TValue> uses less memory than SortedDictionary<TKey, TValue>.
SortedDictionary<TKey, TValue> has faster insertion and removal operations for unsorted data: O(log n) as opposed to O(n) for SortedList<TKey, TValue>.
If the list is populated all at once from sorted data, SortedList<TKey, TValue> is faster than SortedDictionary<TKey, TValue>.
Here is a possible implementation using a SortedDictionary<double, SortedSet<Obj>>:
SortedDictionary<double, SortedSet<Obj>> sortedLookup =
new SortedDictionary<double, SortedSet<Obj>>(); // key is V1 and value all items with that value
internal class ObjV2Comparer : IComparer<Obj>
{
public int Compare(Obj x, Obj y)
{
return x.V2.CompareTo(y.V2);
}
}
private static readonly ObjV2Comparer V2Comparer = new ObjV2Comparer();
public void Add(Obj obj)
{
SortedSet<Obj> set;
bool exists = sortedLookup.TryGetValue(obj.V1, out set);
if(!exists)
set = new SortedSet<Obj>(V2Comparer);
set.Add(obj);
sortedLookup[obj.V1] = set;
}
public Obj GetMaxItem()
{
if (sortedLookup.Count == 0) return null;
Obj maxV1Item = sortedLookup.Last().Value.Last();
return maxV1Item;
}
Obj is your class that contains V1 and V2, i have presumed that V1 is a primitive type like double. GetMaxItem is the method that returns the max-item.
If V1 and V2 can contain duplicates you could try this approach, where the key of each SortedDictionary is the V1 value and the value is another SortedDictionary with the V2-key and all related objects.
SortedDictionary<double, SortedDictionary<double, List<Obj>>> sortedLookup =
new SortedDictionary<double, SortedDictionary<double, List<Obj>>>();
public void Add(Obj obj)
{
SortedDictionary<double, List<Obj>> value;
bool exists = sortedLookup.TryGetValue(obj.V1, out value);
if(!exists)
{
value = new SortedDictionary<double, List<Obj>>(){{obj.V2, new List<Obj>{obj}}};
sortedLookup.Add(obj.V1, value);
}
else
{
List<Obj> list;
exists = value.TryGetValue(obj.V2, out list);
if (!exists)
list = new List<Obj>();
list.Add(obj);
value[obj.V2] = list;
sortedLookup[obj.V1] = value;
}
}
public Obj GetMaxItem()
{
if (sortedLookup.Count == 0) return null;
Obj maxV1Item = sortedLookup.Last().Value.Last().Value.Last();
return maxV1Item;
}
Non-LINQ (I took System.Drawing.Point struct for this example):
static Point GetHighestXY(Point[] points)
{
Point max = default(Point);
for (int i = 0; i < points.Length; i++)
{
if (points[i].X < max.X) continue;
if (points[i].X > max.X) { max = points[i]; }
else { if (points[i].Y > max.Y) max = points[i]; }
}
return max;
}
Usage example:
Point[] pts =
{
new Point(55, 8),
new Point(55, 10),
new Point(10, 10),
new Point(22, 11),
new Point(16, 33),
new Point(4, 104)
};
Point max = GetHighestXY(pts);
Console.WriteLine("X : {0} Y : {1} ", max.X, max.Y);
Result :
As always, if you just want the maximum value, there's no need to do any sorting - Aggregate is O(n):
var maxByBoth = items.Aggregate(
(bestSoFar, current) =>
{
if (current.V1 > bestSoFar.V1)
return current;
if (current.V1 == bestSoFar.V1 && current.V2 > bestSoFar.V2)
return current;
return bestSoFar;
});
Related
This question already has answers here:
How to use LINQ to select object with minimum or maximum property value
(20 answers)
Closed 10 months ago.
Commonly, to find element with property of max value I do like this
var itemWithMaxPropValue = collection.OrderByDescending(x => x.Property).First();
But is it good way from performance point of view? Maybe I should do something like this?
var maxValOfProperty = collection.Max(x => x.Property);
var itemWithMaxPropValue = collection
.Where(x => x.Property == maxValueOfProperty).First();
Sorting is N * log (N) while Max has N only time complexity, so Max is faster. What you're looking for is ArgMax function which Linq doesn't provide, so I suggest implementing it, e.g:
public static class EnumerableExtensions {
public static T ArgMax<T, K>(this IEnumerable<T> source,
Func<T, K> map,
IComparer<K> comparer = null) {
if (Object.ReferenceEquals(null, source))
throw new ArgumentNullException("source");
else if (Object.ReferenceEquals(null, map))
throw new ArgumentNullException("map");
T result = default(T);
K maxKey = default(K);
Boolean first = true;
if (null == comparer)
comparer = Comparer<K>.Default;
foreach (var item in source) {
K key = map(item);
if (first || comparer.Compare(key, maxKey) > 0) {
first = false;
maxKey = key;
result = item;
}
}
if (!first)
return result;
else
throw new ArgumentException("Can't compute ArgMax on empty sequence.", "source");
}
}
So you can put it simply
var itemWithMaxPropValue = collection
.ArgMax(x => x.Property);
Both solutions are not very efficient. First solution involves sorting whole collection. Second solution requires traversing collection two times. But you can find item with max property value in one go without sorting collection. There is MaxBy extension in MoreLINQ library. Or you can implement same functionality:
public static TSource MaxBy<TSource, TProperty>(this IEnumerable<TSource> source,
Func<TSource, TProperty> selector)
{
// check args
using (var iterator = source.GetEnumerator())
{
if (!iterator.MoveNext())
throw new InvalidOperationException();
var max = iterator.Current;
var maxValue = selector(max);
var comparer = Comparer<TProperty>.Default;
while (iterator.MoveNext())
{
var current = iterator.Current;
var currentValue = selector(current);
if (comparer.Compare(currentValue, maxValue) > 0)
{
max = current;
maxValue = currentValue;
}
}
return max;
}
}
Usage is simple:
var itemWithMaxPropValue = collection.MaxBy(x => x.Property);
I will go with Max since it is specifically designed for that purpose. Sorting to find Max value seems to be too much.
Also, I wouldn't use Where for finding the max, but Single - since what we need here is but a Single value.
var maxValOfProperty = collection.Max(x => x.Property);
var itemWithMaxPropValue = collection
.Single(x => x.Property == maxValueOfProperty);
Or alternatively using First (if the collection contains duplicates of max value)
var maxValOfProperty = collection.Max(x => x.Property);
var itemWithMaxPropValue = collection
.First(x => x.Property == maxValueOfProperty);
Or, using MoreLINQ (as suggested by Kathi), you could do it with MaxBy:
var itemWithMaxPropValue = collection.MaxBy(x => x.Property);
Check this post, on answer by Jon Skeet.
The maximum element under some specified function can also be found by means of the following two functions.
static class Tools
{
public static T ArgMax<T, R>(T t1, T t2, Func<T, R> f)
where R : IComparable<R>
{
return f(t1).CompareTo(f(t2)) > 0 ? t1 : t2;
}
public static T ArgMax<T, R>(this IEnumerable<T> Seq, Func<T, R> f)
where R : IComparable<R>
{
return Seq.Aggregate((t1, t2) => ArgMax<T, R>(t1, t2, f));
}
}
The solution above works as follows; the first overload of ArgMax takes a comparator as an argument which maps both instances of T to a type which implements comparability; a maximum of these is returned. The second overload takes a sequence as an argument and simply aggregates the first function. This is the most generic, framework-reusing and structurally sound formulation for maximum search I am aware of; searching the minimum can be implemented in the same way by changing the comparison in the first function.
I'm a little bit surprised that no one mentioned the Aggregate method. Aggregate lets you iterate a collection and return an aggregate value.
An ArgMax function can be implemented in this way:
var maxItem = collection.Aggregate((max, next) => next.Property.CompareTo(max.Property) > 0 ? next : max);
This function will iterate all over the collection and aggregate the item that has the largest Property. This implementation is O(N) which is good.
Please note that the Property getter (or the compared value in general) is called 2N times so don't do this when the value computation is heavy. You can avoid this with another iteration over the array or use the #Sergey Berezovskiy answer which suits all the cases.
But if you need it for simple values, this is a one-line efficient solution
I'm having a problem knowing the best way to make a method to group a list of items into groups of (for example) no more than 3 items. I've created the method below, but without doing a ToList on the group before I return it, I have a problem with it if the list is enumerated multiple times.
The first time it's enumerated is correct, but any additional enumeration is thrown off because the two variables (i and groupKey) appear to be remembered between the iterations.
So the questions are:
Is there a better way to do what I'm trying to achieve?
Is simply ToListing the resulting group before it leaves this method
really such a bad idea?
public static IEnumerable<IGrouping<int, TSource>> GroupBy<TSource>
(this IEnumerable<TSource> source, int itemsPerGroup)
{
const int initial = 1;
int i = initial;
int groupKey = 0;
var groups = source.GroupBy(x =>
{
if (i == initial)
{
groupKey = 0;
}
if (i > initial)
{
//Increase the group key if we've counted past the items per group
if (itemsPerGroup == initial || i % itemsPerGroup == 1)
{
groupKey++;
}
}
i++;
return groupKey;
});
return groups;
}
Here's one way to do this using LINQ...
public static IEnumerable<IGrouping<int, TSource>> GroupBy<TSource>
(this IEnumerable<TSource> source, int itemsPerGroup)
{
return source.Zip(Enumerable.Range(0, source.Count()),
(s, r) => new { Group = r / itemsPerGroup, Item = s })
.GroupBy(i => i.Group, g => g.Item)
.ToList();
}
Live Demo
I think you are looking for something like this:
return source.Select((x, idx) => new { x, idx })
.GroupBy(x => x.idx / itemsPerGroup)
.Select(g => g.Select(a => a.x));
You need to change your return type as IEnumerable<IEnumerable<TSource>>
The problem with using GroupBy() is that unless it somehow has knowledge under the hood that the input is ordered by key value, it has to read the entire sequence and allocate everything to its bucket before it can emit a single group. That's overkill in this case, since the key is a function of its ordinal position within the sequence.
I like the source.Skip(m).Take(n) approach, but that makes assumptions that items in source can be directly addressed. If that's not true or Skip() and Take() have no knowledge of the underlying implementation, then the production of each group is going to be an O(n/2) operation on the average, as it repeatedly iterates over source to produce the group.
This makes the overall partitioning operation, potentially quite expensive.
IF producing a group is an O(n/2) operation on the average, and
Given a group size of s, the production of approximately n/s groups is required,
Then the total cost of the operation is something like O(n2/2s), right?
So, I would do something this, an O(n) operation (feel free to use an IGrouping implementation if you'd like):
public static IEnumerable<KeyValuePair<int,T[]>> Partition<T>( this IEnumerable<T> source , int partitionSize )
{
if ( source == null ) throw new ArgumentNullException("source") ;
if ( partitionSize < 1 ) throw new ArgumentOutOfRangeException("partitionSize") ;
int i = 0 ;
List<T> partition = new List<T>( partitionSize ) ;
foreach( T item in source )
{
partition.Add(item) ;
if ( partition.Count == partitionSize )
{
yield return new KeyValuePair<int,T[]>( ++i , partition.ToArray() ) ;
partition.Clear() ;
}
}
// return the last partition if necessary
if ( partition.Count > 0 )
{
yield return new Partition<int,T>( ++i , items.ToArray() ) ;
}
}
.net Fiddle
Essentially you have an IEnumerable, and you want to group it into an IEnumerable of IGroupables which each contain the key as an index and the group as the values. Your version does seem to accomplish on the first pass, but I think that you can definitely stream line a little bit.
Using skip and take is the most desirable way to accomplish in my opinion, but the custom key for grouping is where there is an issue. There is a way around this which is to create your own class as a grouping template (seen in this answer: https://stackoverflow.com/a/5073144/1026459).
The end result is this:
public static class GroupExtension
{
public static IEnumerable<IGrouping<int, T>> GroupAt<T>(this IEnumerable<T> source, int itemsPerGroup)
{
for(int i = 0; i < (int)Math.Ceiling( (double)source.Count() / itemsPerGroup ); i++)
{
var currentGroup = new Grouping<int,T>{ Key = i };
currentGroup.AddRange(source.Skip(itemsPerGroup*i).Take(itemsPerGroup));
yield return currentGroup;
}
}
private class Grouping<TKey, TElement> : List<TElement>, IGrouping<TKey, TElement>
{
public TKey Key { get; set; }
}
}
And here is the demo in the fiddle which consumes it on a simple string
public class Program
{
public void Main(){
foreach(var p in getLine().Select(s => s).GroupAt(3))
Console.WriteLine(p.Aggregate("",(s,val) => s += val));
}
public string getLine(){ return "Hello World, how are you doing, this just some text to show how the grouping works"; }
}
edit
Alternatively as just an IEnumerable of IEnumerable
public static IEnumerable<IEnumerable<T>> GroupAt<T>(this IEnumerable<T> source, int itemsPerGroup)
{
for(int i = 0; i < (int)Math.Ceiling( (double)source.Count() / itemsPerGroup ); i++)
yield return source.Skip(itemsPerGroup*i).Take(itemsPerGroup);
}
This is based on Selman's Select with index idea, but using ToLookup to combine both the GroupBy and Select together as one:
public static IEnumerable<IEnumerable<TSource>> GroupBy<TSource>
(this IEnumerable<TSource> source, int itemsPerGroup)
{
return source.Select((x, idx) => new { x, idx })
.ToLookup(q => q.idx / itemsPerGroup, q => q.x);
}
The main difference though is that ToLookup actually evaluates results immediately (as concisely explained here: https://stackoverflow.com/a/11969517/7270462), which may or may not be desired.
I need to find if there are 3 identical items in list.
It should compare elements using overridden .Equals() method. I've tried many ways and failed.
It doesn't matter if it returns bool value or items itself.
The function will be called every time after new item is added, so it does not matter how as long as it detects the point when 3 same items are in list.
This is probably something trivial, but my knowledge of Linq is very weak.
Try
return
collection.Any(any => collection.Count(item => item.Equals(any)) == 3);
By grouping items by itself and evaluating if any group contains exactly three items, you will receive expected result.
private bool ContainsTriple<T>(IList<T> items){
return items.GroupBy(i => i).Any(l => l.Count() == 3);
}
To express better my concept:
static class EnumerableExtensions
{
public static IEnumerable<T> FirstRepeatedTimes<T>(this IEnumerable<T> sequence, int threshold)
{
if (!sequence.Any())
throw new ArgumentException("Sequence must contain elements", "sequence");
if (threshold < 2)
throw new ArgumentException("DuplicateCount must be greater than 1", "threshold");
return FirstRepeatedTimesImpl(sequence, threshold);
}
static IEnumerable<T> FirstRepeatedTimesImpl<T>(this IEnumerable<T> sequence, int threshold)
{
var map = new Dictionary<T, int>();
foreach(var e in sequence)
{
if (!map.ContainsKey(e))
map.Add(e, 0);
if (map[e] + 1 == threshold)
{
yield return e;
yield break;
}
map[e] = map[e] + 1;
}
}
}
you would use it like this:
var list = new List<int>() { 1,2,2,3,4,3,3 };
// list contains anything for 3 times?
var found = list.FirstRepeatedTimes(3).Any();
It could potentially consume some more memory, but it enumerates the list at most once. Is this Linq? The way I wrote it, it yields exactly 1 element (the first found), or no element, and you can further compose on top of it if you want. You could use FirstOfDefault() instead of Any(), and have then the found element or 0 (or null if we deal with reference types). This way you have the choice.
It's just another way to see it.
static void Main(string[] args)
{
List<string> col = new List<string>();
col.Add("a");
Console.WriteLine(Has_3(col));
Console.ReadKey();
col.Add("a");
Console.WriteLine(Has_3(col));
Console.ReadKey();
col.Add("a");
Console.WriteLine(Has_3(col));
Console.ReadKey();
col.Add("a");
Console.WriteLine(Has_3(col));
Console.ReadKey();
}
static bool Has_3(List<string> col)
{
return col.Count(x => x == "a").Equals(3);
}
My first thought was that this could probably be done by using the Group() method, something like this:
var ints = new List<int>(new[] { 1, 2, 3, 4, 5, 6, 2, 2 });
var first = ints.GroupBy(n => n)
.Select(g => new { g.Key, Count = g.Count() })
.First(g => g.Count >= 3);
Console.WriteLine("Found {0} instances of {1}", first.Count, first.Key);
This snippet checks for 3 or more of the same item, and selects the first item that meets the criteria, you might want to change this. And adapt it to your specific objects instead of integers.
Here's an extension:
public static bool ContainsNTimes<T>(this IEnumerable<T> sequence, T element, int duplicateCount)
{
if (element == null)
throw new ArgumentNullException("element");
if (!sequence.Any())
throw new ArgumentException("Sequence must contain elements", "sequence");
if (duplicateCount < 1)
throw new ArgumentException("DuplicateCount must be greater 0", "duplicateCount");
bool containsNTimes = sequence.Where(i => i.Equals(element))
.Take(duplicateCount)
.Count() == duplicateCount;
return containsNTimes;
}
Usage:
var list = new List<int>() { 1,2,2,3,4,3,3 };
// list contains 2 for 3 times?
bool contains2ThreeTimes = list.ContainsNTimes(2, 3);
// any element in the list iscontained 3 times (or more)?
bool anyContains3Times = list.Any(i => list.ContainsNTimes(i, 3));
Console.WriteLine("List contains 2 for 3 times? " + contains2ThreeTimes); // false
Console.WriteLine("Any element in the list is contained 3 times (or more)? " + anyContains3Times); // true (3)
Demo: http://ideone.com/Ozk9v
Should be quite efficient since it uses deferred execution. It enumerates the sequences until n-items were found.
I have a Dictionary
Dictionary<Location2D, int> h_scores = new Dictionary<Location2D, int>();
and I want to select the Key // which is Location2D by the minimum int value.
I tried
h_scores.Min().Key; // not working
h_scores.OrderBy(x => x.Value).Select(y=> y.Key).Min(); //error At least one object must implement IComparable.
so how can I select a key by the smallest int value?
You just need to use the right overload of Min:
val minKey = h_scores.Min(s => s.Value).Key;
Update
Didn't pay attention to the return value of the overload for Min. You are definitely looking for MinBy from Jon Skeet's morelinq:
val minKey = h_scores.MinBy(s => s.Value).Key;
Just for the sake of diversity, the solution which doesn't need external dependencies (e.g. MoreLinq) and is O(n) in contrast to OrderBy() solutions which are at least O(n*log(n)):
var minKey =
h_scores.Aggregate(h_scores.First(), (min, curr) => curr.Value < min.Value ? curr : min).Key;
If you order them by the Value the first one will be the one with the minimum
h_scores.OrderBy(x => x.Value).First().Select(y=> y.Key);
I don't know what a Location2D is but you can use the following example to do what you want. Just sub in your class instead of string. Also, because values are not guaranteed to be unique in a Dictionary (but may be in your case), you will likely want to do a .Single() on the keys enumeration.
[Test]
public void Test()
{
var dictionary = new Dictionary<string, int>
{
{ "first", 2 },
{ "second", 1 },
{ "third", 3 },
{ "fourth", 1 }
};
int min = dictionary.Values.Min();
IEnumerable<string> keys = dictionary.Keys.Where(key => dictionary[key] == min);
Assert.That(keys.Count(), Is.EqualTo(2));
Assert.That(keys.Contains("second"), Is.True);
Assert.That(keys.Contains("fourth"), Is.True);
}
This question already has answers here:
How to use LINQ to select object with minimum or maximum property value
(20 answers)
Closed 7 years ago.
I have a list of objects that have two int properties. The list is the output of another linq query. The object:
public class DimensionPair
{
public int Height { get; set; }
public int Width { get; set; }
}
I want to find and return the object in the list which has the largest Height property value.
I can manage to get the highest value of the Height value but not the object itself.
Can I do this with Linq? How?
We have an extension method to do exactly this in MoreLINQ. You can look at the implementation there, but basically it's a case of iterating through the data, remembering the maximum element we've seen so far and the maximum value it produced under the projection.
In your case you'd do something like:
var item = items.MaxBy(x => x.Height);
This is better (IMO) than any of the solutions presented here other than Mehrdad's second solution (which is basically the same as MaxBy):
It's O(n) unlike the previous accepted answer which finds the maximum value on every iteration (making it O(n^2))
The ordering solution is O(n log n)
Taking the Max value and then finding the first element with that value is O(n), but iterates over the sequence twice. Where possible, you should use LINQ in a single-pass fashion.
It's a lot simpler to read and understand than the aggregate version, and only evaluates the projection once per element
This would require a sort (O(n log n)) but is very simple and flexible. Another advantage is being able to use it with LINQ to SQL:
var maxObject = list.OrderByDescending(item => item.Height).First();
Note that this has the advantage of enumerating the list sequence just once. While it might not matter if list is a List<T> that doesn't change in the meantime, it could matter for arbitrary IEnumerable<T> objects. Nothing guarantees that the sequence doesn't change in different enumerations so methods that are doing it multiple times can be dangerous (and inefficient, depending on the nature of the sequence). However, it's still a less than ideal solution for large sequences. I suggest writing your own MaxObject extension manually if you have a large set of items to be able to do it in one pass without sorting and other stuff whatsoever (O(n)):
static class EnumerableExtensions {
public static T MaxObject<T,U>(this IEnumerable<T> source, Func<T,U> selector)
where U : IComparable<U> {
if (source == null) throw new ArgumentNullException("source");
bool first = true;
T maxObj = default(T);
U maxKey = default(U);
foreach (var item in source) {
if (first) {
maxObj = item;
maxKey = selector(maxObj);
first = false;
} else {
U currentKey = selector(item);
if (currentKey.CompareTo(maxKey) > 0) {
maxKey = currentKey;
maxObj = item;
}
}
}
if (first) throw new InvalidOperationException("Sequence is empty.");
return maxObj;
}
}
and use it with:
var maxObject = list.MaxObject(item => item.Height);
Doing an ordering and then selecting the first item is wasting a lot of time ordering the items after the first one. You don't care about the order of those.
Instead you can use the aggregate function to select the best item based on what you're looking for.
var maxHeight = dimensions
.Aggregate((agg, next) =>
next.Height > agg.Height ? next : agg);
var maxHeightAndWidth = dimensions
.Aggregate((agg, next) =>
next.Height >= agg.Height && next.Width >= agg.Width ? next: agg);
And why don't you try with this ??? :
var itemsMax = items.Where(x => x.Height == items.Max(y => y.Height));
OR more optimise :
var itemMaxHeight = items.Max(y => y.Height);
var itemsMax = items.Where(x => x.Height == itemMaxHeight);
mmm ?
The answers so far are great! But I see a need for a solution with the following constraints:
Plain, concise LINQ;
O(n) complexity;
Do not evaluate the property more than once per element.
Here it is:
public static T MaxBy<T, R>(this IEnumerable<T> en, Func<T, R> evaluate) where R : IComparable<R> {
return en.Select(t => new Tuple<T, R>(t, evaluate(t)))
.Aggregate((max, next) => next.Item2.CompareTo(max.Item2) > 0 ? next : max).Item1;
}
public static T MinBy<T, R>(this IEnumerable<T> en, Func<T, R> evaluate) where R : IComparable<R> {
return en.Select(t => new Tuple<T, R>(t, evaluate(t)))
.Aggregate((max, next) => next.Item2.CompareTo(max.Item2) < 0 ? next : max).Item1;
}
Usage:
IEnumerable<Tuple<string, int>> list = new[] {
new Tuple<string, int>("other", 2),
new Tuple<string, int>("max", 4),
new Tuple<string, int>("min", 1),
new Tuple<string, int>("other", 3),
};
Tuple<string, int> min = list.MinBy(x => x.Item2); // "min", 1
Tuple<string, int> max = list.MaxBy(x => x.Item2); // "max", 4
I believe that sorting by the column you want to get the MAX of and then grabbing the first should work. However, if there are multiple objects with the same MAX value, only one will be grabbed:
private void Test()
{
test v1 = new test();
v1.Id = 12;
test v2 = new test();
v2.Id = 12;
test v3 = new test();
v3.Id = 12;
List<test> arr = new List<test>();
arr.Add(v1);
arr.Add(v2);
arr.Add(v3);
test max = arr.OrderByDescending(t => t.Id).First();
}
class test
{
public int Id { get; set; }
}
In NHibernate (with NHibernate.Linq) you could do it as follows:
return session.Query<T>()
.Single(a => a.Filter == filter &&
a.Id == session.Query<T>()
.Where(a2 => a2.Filter == filter)
.Max(a2 => a2.Id));
Which will generate SQL like follows:
select *
from TableName foo
where foo.Filter = 'Filter On String'
and foo.Id = (select cast(max(bar.RowVersion) as INT)
from TableName bar
where bar.Name = 'Filter On String')
Which seems pretty efficient to me.
Based on Cameron's initial answer, here is what I've just added at my enhanced version of SilverFlow library's FloatingWindowHost (copying from FloatingWindowHost.cs at http://clipflair.codeplex.com source code)
public int MaxZIndex
{
get {
return FloatingWindows.Aggregate(-1, (maxZIndex, window) => {
int w = Canvas.GetZIndex(window);
return (w > maxZIndex) ? w : maxZIndex;
});
}
}
private void SetTopmost(UIElement element)
{
if (element == null)
throw new ArgumentNullException("element");
Canvas.SetZIndex(element, MaxZIndex + 1);
}
Worth noting regarding the code above that Canvas.ZIndex is an attached property available for UIElements in various containers, not just used when being hosted in a Canvas (see Controlling rendering order (ZOrder) in Silverlight without using the Canvas control). Guess one could even make a SetTopmost and SetBottomMost static extension method for UIElement easily by adapting this code.
You can also upgrade Mehrdad Afshari's solution by rewriting the extention method to faster (and better looking) one:
static class EnumerableExtensions
{
public static T MaxElement<T, R>(this IEnumerable<T> container, Func<T, R> valuingFoo) where R : IComparable
{
var enumerator = container.GetEnumerator();
if (!enumerator.MoveNext())
throw new ArgumentException("Container is empty!");
var maxElem = enumerator.Current;
var maxVal = valuingFoo(maxElem);
while (enumerator.MoveNext())
{
var currVal = valuingFoo(enumerator.Current);
if (currVal.CompareTo(maxVal) > 0)
{
maxVal = currVal;
maxElem = enumerator.Current;
}
}
return maxElem;
}
}
And then just use it:
var maxObject = list.MaxElement(item => item.Height);
That name will be clear to people using C++ (because there is std::max_element in there).