子阵列上的C#LINQ OrderBy

时间:2019-03-31 06:32:31

标签: c# linq

使用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的精神。

2 个答案:

答案 0 :(得分:5)

您可以使用SkipTake来达到目标​​。

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

答案 1 :(得分:-1)

反复调用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();
    }
}