我有一个具有两个int属性的对象列表。该列表是另一个linq查询的输出。对象:
public class DimensionPair
{
public int Height { get; set; }
public int Width { get; set; }
}
我想在列表中找到并返回具有最大Height属性值的对象。
我可以设法获得高度值的最大值,但不是对象本身。
我可以用Linq做这个吗?如何?
我有一个具有两个int属性的对象列表。该列表是另一个linq查询的输出。对象:
public class DimensionPair
{
public int Height { get; set; }
public int Width { get; set; }
}
我想在列表中找到并返回具有最大Height属性值的对象。
我可以设法获得高度值的最大值,但不是对象本身。
我可以用Linq做这个吗?如何?
当前回答
我相信按你想要的列排序,然后抓取第一个应该是可行的。然而,如果有多个对象具有相同的MAX值,则只有一个对象会被抓取:
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; }
}
其他回答
我相信按你想要的列排序,然后抓取第一个应该是可行的。然而,如果有多个对象具有相同的MAX值,则只有一个对象会被抓取:
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; }
}
你也可以通过重写扩展方法来升级Mehrdad Afshari的解决方案,使其更快(更好看):
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);
这个名称对于使用c++的人来说是清楚的(因为这里有std::max_element)。
在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));
它将生成如下所示的SQL:
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')
这对我来说很有效。
这将需要排序(O(n log n)),但非常简单和灵活。另一个优点是可以与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;
}
}
并将其用于:
var maxObject = list.MaxObject(item => item.Height);
你为什么不试试这个??:
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);
嗯?