C# 排序列表并根据排序依据选择对象
我有一个C# 排序列表并根据排序依据选择对象,c#,list,linq,C#,List,Linq,我有一个列表,其中包含状态和日期字段。我想返回一个MyClass,其中Status=X 问题是列表中可能有多个,在这种情况下,我希望在Date上排序并返回最新的一个 这可以在LINQ中的单个表达式中完成吗?您可以使用lambda表达式: var yourResult = dbo.YourList.OrderByDescending(t=>t.Date).FirstOrDefault(t=>t.Status == 'X'); 如果列表已位于内存中,请尝试以下操作: var answe
列表
,其中包含状态
和日期
字段。我想返回一个MyClass
,其中Status=X
问题是列表中可能有多个,在这种情况下,我希望在Date
上排序并返回最新的一个
这可以在LINQ中的单个表达式中完成吗?您可以使用lambda表达式:
var yourResult = dbo.YourList.OrderByDescending(t=>t.Date).FirstOrDefault(t=>t.Status == 'X');
如果
列表
已位于内存中,请尝试以下操作:
var answer = list.Where(x => x.Status == X).OrderBy(x => x.Date).LastOrDefault();
对于实体框架,请尝试另一种方法:
var answer = context.Table.Where(x => x.Status == X).OrderByDescending(x => x.Date).FirstOrDefault();
因此,您需要一系列的
MyClass
对象和一个X
对象,并希望找到最新的MyClass
对象,该对象的Status
值等于X
var result = myList.Where(myItem => myItem.Status == X)
.OrderByDescending(myItem => myItem.Date)
.FirstOrDefault();
虽然这会起作用,但排序不是很有效:在找到第一个元素后,它会对第二个、第三个等元素进行排序,而您知道它不会使用这些其他元素,那么为什么要对它们进行排序呢?如果使用聚合,则只需枚举一次
var result = myList.Where(...)
.Aggregate( (newestItem, nextItem) => (newestItem.Date < nextItem.Date) ?
newestItem : nextItem);
这将只扫描您的序列一次。
list.Where(x=>x.Status==x).OrderBy(x=>x.Date).Last()
或MaxyBy from MoreLINQ:list.Where(x=>x.Status==x).MaxBy(x=>x.Date).First()@SlavaUtesinov您最好添加您的建议作为答案首先排序然后再进行选择的意义是什么?如果有1M条记录会发生什么?这将节省一次额外检查,但是,对于较大的列表,它可能会略微降低性能。假设1M条记录的90%状态为“X”。不要忘记,在循环中检查是一个O(N)
操作,而最佳排序算法的复杂性为O(N*log(N))
这只是实施细节。
static TResult GetNewestOrDefault<TSource, TResult>(this IEnumerable<TSource> source,
Func<Tsource, DateTime> dateSelector)
{
var enumerator = source.GetEnumerator();
if (enumerator.MoveNext())
{ // at least one element; initialize newest:
TSource newestElement = enumerator.Current;
DateTime newestDate = dateSelector(newest);
// scan the rest of the sequence and check if newer:
while (enumerator.MoveNext())
{
Tsource nextElement = enumerator.Current;
Datetime nextDate = dateSelector(nextElement);
// if next element has a newer date, remember it as newest:
if (newestDate < nextDate
{
newestElement = nextElement;
newestDate = nextDate,
}
}
// scanned all elements exactly once
return newestElement;
}
else
// empty sequence, return default
return default(TResult);
}
MyClass result = myList.Where(myItem => myItem.Status == X)
.GetNewestOrDefault();