通常,要查找具有最大值属性的元素,我喜欢这个
var itemWithMaxPropValue = collection.OrderByDescending(x => x.Property).First();
但从性能的角度来看它是好方法吗?也许我应该做这样的事情?
var maxValOfProperty = collection.Max(x => x.Property);
var itemWithMaxPropValue = collection
.Where(x => x.Property == maxValueOfProperty).First();
答案 0 :(得分:5)
排序为N * log (N)
,而Max只有N
时间复杂度,因此Max
更快。你正在寻找的是{em> Linq 没有提供的ArgMax
函数,所以我建议实现它,例如:
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");
}
}
所以你可以简单地说出来
var itemWithMaxPropValue = collection
.ArgMax(x => x.Property);
答案 1 :(得分:4)
我会选择Max
,因为它是专为此目的而设计的。排序以查找Max
值似乎太多了。
另外,我不会使用Where
来查找最大值,而是使用Single
- 因为我们需要的只是Single
值。
var maxValOfProperty = collection.Max(x => x.Property);
var itemWithMaxPropValue = collection
.Single(x => x.Property == maxValueOfProperty);
或者使用First
(如果集合包含最大值的重复)
var maxValOfProperty = collection.Max(x => x.Property);
var itemWithMaxPropValue = collection
.First(x => x.Property == maxValueOfProperty);
或者,使用MoreLINQ(由Kathi建议),您可以使用MaxBy
执行此操作:
var itemWithMaxPropValue = collection.MaxBy(x => x.Property);
答案 2 :(得分:4)
两种解决方案效率都不高。第一个解决方案涉及整个集合。第二种解决方案需要遍历收集两次。但是您可以一次性找到具有最大属性值的项目而无需对集合进行排序。 MoreLINQ库中有MaxBy扩展名。或者您可以实现相同的功能:
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;
}
}
用法很简单:
var itemWithMaxPropValue = collection.MaxBy(x => x.Property);
答案 3 :(得分:0)
某些指定功能下的最大元素也可以通过以下两个函数找到。
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));
}
}
上述解决方案的工作原理如下: ArgMax
的第一个重载将比较器作为参数,将T
的两个实例映射到实现可比性的类型;返回最多这些。第二个重载将序列作为参数,并简单地聚合第一个函数。对于我所知道的最大搜索,这是最通用的,框架重用和结构合理的公式;通过改变第一个函数中的比较,可以以相同的方式实现搜索最小值。