簡體   English   中英

子數組上的 C# LINQ OrderBy

[英]C# LINQ OrderBy on sub array

使用 C# LINQ,我們是否可以只對 List 的一系列元素進行 OrderBy 並保留其他元素?

例如,輸入列表是 {"a","b","c","d","e"},一個想象的 OrderByDescending 是這樣的:

OrderByDescending(delegate d,int start_index,int end_index)

l=l.OrderByDescending(x=>x,1,3).ToList();

結果是:{"a","d","c","b","e"}

沒有這個功能,我需要拆分/LINQ Orderby/重新加入,這失去了LINQ的精神。

您可以使用Skip and Take來實現這一點。

var input = new[] { "a", "b", "c", "d", "e" };

var res = input.Take(1)
               .Concat(input.Skip(1).Take(3).OrderByDescending(e => e))
               .Concat(input.Skip(4));

你也可以做一個像這樣的擴展方法

public static class IEnumerableExt
{
    public static IEnumerable<TSource> OrderRangeByDescending<TSource, TKey>(this IEnumerable<TSource> input, Func<TSource, TKey> keySelector, int from, int length)
    {
        return input.Take(from)
                    .Concat(input.Skip(from).Take(length).OrderByDescending(keySelector))
                    .Concat(input.Skip(from + length));
    }

    public static IEnumerable<TSource> OrderRangeBy<TSource, TKey>(this IEnumerable<TSource> input, Func<TSource, TKey> keySelector, int from, int length)
    {
        return input.Take(from)
                    .Concat(input.Skip(from).Take(length).OrderBy(keySelector))
                    .Concat(input.Skip(from + length));
    }
}
var input = new[] { "a", "b", "c", "d", "e" };

var res = input.OrderRangeByDescending(e => e, 1, 3);

重復調用SkipTake可能會影響性能,特別是如果源是由密集計算生成的。 最佳解決方案將要求源的讀取僅發生一次。 這可以通過將源拆分為多個枚舉來實現,但使用單個枚舉器。 擁有這樣一個 Splitter 將允許我們很容易地實現OrderRangeBy / OrderRangeByDescending方法:

public static IEnumerable<TSource> OrderRangeBy<TSource, TKey>(
    this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
    int startIndex, int endIndexExclusive)
{
    var parts = source.Split(startIndex, endIndexExclusive);
    return parts[0].Concat(parts[1].OrderBy(keySelector)).Concat(parts[2]);
}

public static IEnumerable<TSource> OrderRangeByDescending<TSource, TKey>(
    this IEnumerable<TSource> source, Func<TSource, TKey> keySelector,
    int startIndex, int endIndexExclusive)
{
    var parts = source.Split(startIndex, endIndexExclusive);
    return parts[0].Concat(parts[1].OrderByDescending(keySelector)).Concat(parts[2]);
}

這是 Splitter 的一個實現:

public static IEnumerable<TSource>[] Split<TSource>(
    this IEnumerable<TSource> source, params int[] indices)
{
    var parts = new IEnumerable<TSource>[indices.Length + 1];
    var enumerator = source.GetEnumerator();
    int index = 0;
    for (int i = 0; i < indices.Length; i++)
    {
        parts[i] = GetPart(indices[i]);
    }
    parts[indices.Length] = GetPart(Int32.MaxValue);
    return parts;
    IEnumerable<TSource> GetPart(int maxIndexExclusive)
    {
        if (index >= maxIndexExclusive) goto finish;
        while (enumerator.MoveNext())
        {
            yield return enumerator.Current;
            index++;
            if (index >= maxIndexExclusive) break;
        }
        finish: if (maxIndexExclusive == Int32.MaxValue) enumerator.Dispose();
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM