我有一个具有两个int属性的对象列表.该列表是另一个linq查询的输出.物体:
public class DimensionPair { public int Height { get; set; } public int Width { get; set; } }
我想找到并返回列表中具有最大Height
属性值的对象.
我可以设法获得值的最高值,Height
但不能获得对象本身.
我可以用Linq做到这一点吗?怎么样?
我们有一个扩展方法,可以在MoreLINQ中完成此操作.您可以查看那里的实现,但基本上是迭代数据的情况,记住我们到目前为止看到的最大元素以及它在投影下产生的最大值.
在你的情况下你会做类似的事情:
var item = items.MaxBy(x => x.Height);
除了Mehrdad的第二个解决方案(基本相同)之外,这比其他任何解决方案更好(IMO MaxBy
):
它是O(n)不同于先前接受的答案,它在每次迭代中找到最大值(使其为O(n ^ 2))
订购解决方案是O(n log n)
取Max
的值,然后找出与该值的第一个元素是O(n),但在序列迭代两次.在可能的情况下,您应该以单通方式使用LINQ.
阅读和理解比聚合版本简单得多,并且每个元素只评估一次投影
这需要排序(O(n log n)),但非常简单和灵活.另一个优点是能够将它与LINQ to SQL一起使用:
var maxObject = list.OrderByDescending(item => item.Height).First();
请注意,这具有list
仅枚举序列一次的优点.虽然在此期间如果不改变可能无关紧要,但它对任意对象list
都很List
重要IEnumerable
.没有什么能保证序列在不同的枚举中不会改变,因此多次执行它的方法可能是危险的(并且效率低,取决于序列的性质).然而,对于大型序列来说,它仍然不是理想的解决方案.我建议MaxObject
手动编写自己的扩展,如果你有一大堆项目可以在一次通过中完成,而无需排序和其他任何东西(O(n)):
static class EnumerableExtensions { public static T MaxObject(this IEnumerable source, Func selector) where U : IComparable { 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; } }
并使用它:
var maxObject = list.MaxObject(item => item.Height);
进行订购然后选择第一项是浪费了大量时间在第一项之后订购商品.你不关心那些的顺序.
相反,您可以使用聚合函数根据您要查找的内容选择最佳项目.
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);
你为什么不尝试这个?:
var itemsMax = items.Where(x => x.Height == items.Max(y => y.Height));
或者更优化:
var itemMaxHeight = items.Max(y => y.Height); var itemsMax = items.Where(x => x.Height == itemMaxHeight);
嗯?
到目前为止答案很棒!但我认为需要一个具有以下约束的解决方案:
简洁明了的LINQ;
O(n)复杂性;
不要每个元素多次评估该属性.
这里是:
public static T MaxBy(this IEnumerable en, Func evaluate) where R : IComparable { return en.Select(t => new Tuple (t, evaluate(t))) .Aggregate((max, next) => next.Item2.CompareTo(max.Item2) > 0 ? next : max).Item1; } public static T MinBy (this IEnumerable en, Func evaluate) where R : IComparable { return en.Select(t => new Tuple (t, evaluate(t))) .Aggregate((max, next) => next.Item2.CompareTo(max.Item2) < 0 ? next : max).Item1; }
用法:
IEnumerable> list = new[] { new Tuple ("other", 2), new Tuple ("max", 4), new Tuple ("min", 1), new Tuple ("other", 3), }; Tuple min = list.MinBy(x => x.Item2); // "min", 1 Tuple max = list.MaxBy(x => x.Item2); // "max", 4