C# 如何对集合中所有对象的属性执行.Max(),并返回具有最大值的对象
我有一个具有两个int属性的对象列表。该列表是另一个linq查询的输出。对象:C# 如何对集合中所有对象的属性执行.Max(),并返回具有最大值的对象,c#,linq,object,max,C#,Linq,Object,Max,我有一个具有两个int属性的对象列表。该列表是另一个linq查询的输出。对象: public class DimensionPair { public int Height { get; set; } public int Width { get; set; } } 我想在列表中找到并返回属性值最大的对象 我可以设法获得高度值的最高值,但不能获得对象本身 我能和Linq一起做这个吗?如何进行?这需要排序(O(n logn)),但非常简单和灵活。另一个优势是能够将其与LINQ
public class DimensionPair
{
public int Height { get; set; }
public int Width { get; set; }
}
我想在列表中找到并返回属性值最大的对象
我可以设法获得高度
值的最高值,但不能获得对象本身
我能和Linq一起做这个吗?如何进行?这需要排序(O(n logn)),但非常简单和灵活。另一个优势是能够将其与LINQ to SQL结合使用:
var maxObject = list.OrderByDescending(item => item.Height).First();
注意,这样做的优点是只枚举一次列表
序列。虽然如果list
是一个同时不变的list
,这可能无关紧要,但对于任意IEnumerable
对象来说,这可能很重要。没有任何东西可以保证序列不会在不同的枚举中更改,因此多次执行该操作的方法可能是危险的(并且效率低下,这取决于序列的性质)。然而,对于大序列来说,这仍然不是一个理想的解决方案。如果您有大量的项目可以一次完成,而无需排序和其他任何东西,我建议您手动编写自己的MaxObject
扩展(O(n)):
我相信按你想得到的最大值的列排序,然后抓住第一个应该是可行的。但是,如果有多个具有相同最大值的对象,则只会抓取一个:
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; }
}
private void Test()
{
测试v1=新测试();
v1.Id=12;
测试v2=新测试();
v2.Id=12;
测试v3=新测试();
v3.Id=12;
List arr=新列表();
arr.Add(v1);
arr.Add(v2);
arr.Add(v3);
testmax=arr.OrderByDescending(t=>t.Id).First();
}
课堂测试
{
公共int Id{get;set;}
}
先下单,然后再选择第一个项目,这会浪费大量时间在第一个项目之后再下单。你不在乎这些东西的顺序
相反,您可以使用聚合函数根据所需内容选择最佳项目
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 item = items.MaxBy(x => x.Height);
这比这里介绍的任何解决方案都好(IMO),而不是Mehrdad的第二个解决方案(基本上与MaxBy
)相同):
- 它是O(n),不同于在每次迭代中找到最大值(使其为O(n^2))
- 排序解决方案是O(n logn)
- 取
值,然后找到具有该值的第一个元素是O(n),但在序列上迭代两次。在可能的情况下,应该以单通道方式使用LINQMax
- 与聚合版本相比,它的阅读和理解要简单得多,并且每个元素只计算一次投影
- 你为什么不试试这个??:
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);
mmm?在NHibernate中(使用NHibernate.Linq),您可以按如下方式执行:
return session.Query<T>()
.Single(a => a.Filter == filter &&
a.Id == session.Query<T>()
.Where(a2 => a2.Filter == filter)
.Max(a2 => a2.Id));
这对我来说似乎非常有效。根据Cameron的初步回答,以下是我刚刚在增强版SilverFlow库的FloatingWindowHost中添加的内容(从源代码处的FloatingWindowHost.cs复制)
值得注意的是,关于上面的代码,Canvas.ZIndex是一个附加属性,可用于各种容器中的UIElements,而不仅仅是在画布中托管时使用(请参阅)。通过修改此代码,您甚至可以轻松地为UIElement创建SetTopmost和SetBottomMost静态扩展方法。您还可以通过将扩展方法重写为更快(更好看)的方法来升级Mehrdad Afshari的解决方案:
使用C++的人将清楚这个名字(因为在那里有STD::Max元素)。但我认为需要一个具有以下限制的解决方案:
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;
}
public static T MaxBy(此IEnumerable en,Func evaluate),其中R:IComparable{
返回en.Select(t=>newtuple(t,evaluate(t)))
.Aggregate((max,next)=>next.Item2.CompareTo(max.Item2)>0?next:max.Item1;
}
公共静态T MinBy(此IEnumerable en,Func evaluate),其中R:i可比较{
返回en.Select(t=>newtuple(t,evaluate(t)))
.Aggregate((最大,下一个)=>next.Item2.CompareTo(最大项2)<0?下一个:最大)。Item1;
}
用法:
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
IEnumerable list=new[]{
新元组(“其他”,2),
新元组(“max”,4),
新元组(“min”,1),
新元组(“其他”,3),
};
Tuple min=list.MinBy(x=>x.Item2);//“min”,1
Tuple max=list.MaxBy(x=>x.Item2);//“max”,4
Rats,在我发布之前没有看到这一点。这基本上就是我们在MoreLINQ中所做的,除了我们直接使用GetEnumerator进行迭代,而不是使用“first”标志。我认为这使代码更简单一些。我们还允许使用Comparer并允许传入一个,而不是要求U实现IComparable,但这是一个次要问题。最后一部分是一个简单问题的许多不必要的复杂性。这是一个更一般问题的解决方案。基本上,您可以声明这样一种扩展方法,以便在需要时将复杂性抽象掉。这难道不是软件开发的工作方式吗?为了完整性,有没有理由选择OrderByDescending().First()
或OrderBy().Last()
?我在代码中使用第二个选项(至少更短),因为我认为两者的成本相同?(编辑:好吧,没关系…)因为这是O(n^2)。对于列表中的每个项目,它将遍历所有项目,并找到高度最大的项目,然后检查当前项目是否存在
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')
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);
}
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;
}
}
var maxObject = list.MaxElement(item => item.Height);
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;
}
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