我想做这样的事情(如下),但不确定是否有正式/优化语法这样做?
.Orderby(i => i.Value1)
.Take("Bottom 100 & Top 100")
.Orderby(i => i.Value2);
Run Code Online (Sandbox Code Playgroud)
基本上,我想按一个变量排序,然后取前100和下100,然后用另一个变量对这些结果进行排序.
有什么建议?
T_D*_*T_D 26
var sorted = list.OrderBy(i => i.Value);
var top100 = sorted.Take(100);
var last100 = sorted.Reverse().Take(100);
var result = top100.Concat(last100).OrderBy(i => i.Value2);
Run Code Online (Sandbox Code Playgroud)
我不知道你是否想要Concat或Union最后.Concat将组合两个列表的所有条目,即使有相似的条目,如果您的原始列表包含少于200个条目.Union只会添加来自last100但尚未进入top100的东西.
有些事情不明确但应该考虑:
如果list是IQueryable一个db,那么建议使用ToArray()或者ToList(),例如
var sorted = list.OrderBy(i => i.Value).ToArray();
Run Code Online (Sandbox Code Playgroud)
在开始.这样,只有一个数据库查询完成,其余查询在内存中完成.
该Reverse方法没有按照我希望的方式进行优化,但它不应该是一个问题,因为在这里排序列表是真正的交易.但是对于记录,这里的其他答案中解释的跳过方法可能要快一点,但需要知道列表中的元素数量.
如果list是一个LinkedList或另一个实现IList的类,则该Reverse方法可以以优化的方式完成.
你可以使用这样的扩展方法:
public static IEnumerable<T> TakeFirstAndLast<T>(this IEnumerable<T> source, int count)
{
var first = new List<T>();
var last = new LinkedList<T>();
foreach (var item in source)
{
if (first.Count < count)
first.Add(item);
if (last.Count >= count)
last.RemoveFirst();
last.AddLast(item);
}
return first.Concat(last);
}
Run Code Online (Sandbox Code Playgroud)
(我正在使用LinkedList<T>for,last因为它可以删除项目O(1))
你可以像这样使用它:
.Orderby(i => i.Value1)
.TakeFirstAndLast(100)
.Orderby(i => i.Value2);
Run Code Online (Sandbox Code Playgroud)
请注意,它不处理少于200个项目的情况:如果是这种情况,您将获得重复项.Distinct如有必要,您可以删除它们.
分别取前 100 个和后 100 个并将它们合并:
var tempresults = yourenumerable.OrderBy(i => i.Value1);
var results = tempresults.Take(100);
results = results.Union(tempresults.Skip(tempresults.Count() - 100).Take(100))
.OrderBy(i => i.Value2);
Run Code Online (Sandbox Code Playgroud)