使用LINQ占据前100名和后100名?

use*_*988 21 c# linq

我想做这样的事情(如下),但不确定是否有正式/优化语法这样做?

.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)

我不知道你是否想要ConcatUnion最后.Concat将组合两个列表的所有条目,即使有相似的条目,如果您的原始列表包含少于200个条目.Union只会添加来自last100但尚未进入top100的东西.

有些事情不明确但应该考虑:

  • 如果listIQueryable一个db,那么建议使用ToArray()或者ToList(),例如

    var sorted = list.OrderBy(i => i.Value).ToArray();
    
    Run Code Online (Sandbox Code Playgroud)

    在开始.这样,只有一个数据库查询完成,其余查询在内存中完成.

  • Reverse方法没有按照我希望的方式进行优化,但它不应该是一个问题,因为在这里排序列表是真正的交易.但是对于记录,这里的其他答案中解释的跳过方法可能要快一点,但需要知道列表中的元素数量.

  • 如果list是一个LinkedList或另一个实现IList的类,则该Reverse方法可以以优化的方式完成.

  • 如果我们将`list`作为一个IQueryable到DB来返回数以千计的扩展记录,这可能是一个非常大的性能问题 - 我很确定Reverse将从DB中读取一大堆记录来运行.我认为`list.Skip(list.Count() - 100).Take(100)`会更好而不是`reverse ... take`,即使对`Count`有额外的查询 (4认同)

Tho*_*que 6

你可以使用这样的扩展方法:

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如有必要,您可以删除它们.


Gia*_*los 5

分别取前 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)

  • `Union` 将跳过重复的记录,您可能需要使用 `Concat` 代替 (4认同)