美文网首页
c# MoreLinq 之 AggregateRight

c# MoreLinq 之 AggregateRight

作者: wwmin_ | 来源:发表于2021-02-24 18:08 被阅读0次

    前言

    本系列是对MoreLinq库的学习与总结,分析各个Api的实现方式及用法,也为能写出更高效的Linq打下基础。

    AggregateRight 从右到左迭代列表

    • 应用
    void AggregateRightTest()
    {
        var num = Enumerable.Range(1, 5).Select(i => i.ToString());
        //字符窜内插值大括号:使用两个{{、}},参考:https://docs.microsoft.com/zh-cn/dotnet/standard/base-types/composite-formatting#escaping-braces
        string result = num.Aggregate((a, b) => $"{{{a}}}/{{{b}}}");//从前向后叠加
        result.Dump("Aggregate");//{{{{1}/{2}}/{3}}/{4}}/{5}
        string resultRight = num.AggregateRight((a, b) => $"{{{a}}}/{{{b}}}");//从后向前叠加
        resultRight.Dump("AggregateRightTest");//{1}/{{2}/{{3}/{{4}/{5}}}}
    }
    

    对比可以看到,从右向左遍历的结果是将b作为初始值,且整体是倒序的

    • 源码:
    public static class MoreEnumerable
    {
        public static TSource AggregateRight<TSource>(this IEnumerable<TSource> source, Func<TSource, TSource, TSource> func)
        {
            if (source == null) throw new ArgumentNullException(nameof(source));
            if (source == null) throw new ArgumentNullException(nameof(func));
            var list = source.ToListLike();
            if (list.Count == 0) throw new InvalidOperationException("Sequence contains no elements.");
            return AggregateRightImpl(list, list[list.Count - 1], func, list.Count - 1);
        }
    
        static TResult AggregateRightImpl<TSource, TResult>(IListLike<TSource> list, TResult accumulator, Func<TSource, TResult, TResult> func, int i)
        {
            while (i-- > 0)
            {
                accumulator = func(list[i], accumulator);
            }
            return accumulator;
        }
    }
    

    分析:
    最终调用的 AggregateRightImpl 赋值都是从后到前的,使用i--方式倒序遍历。其中还涉及到了列表的浅复制类ListLike。

    ListLike class定义如下:

    public interface IListLike<out T>
    {
        int Count { get; }
        T this[int index] { get; }
    }
    public static class ListLike
    {
        public static IListLike<T> ToListLike<T>(this IEnumerable<T> source) => source switch
        {
            null => throw new ArgumentNullException(nameof(source)),
            IList<T> list => new List<T>(list),
            IReadOnlyList<T> list => new ReadOnlyList<T>(list),
            _ => null!
        };
    
        sealed class List<T> : IListLike<T>
        {
            readonly IList<T> _list;
            public List(IList<T> list) => _list = list ?? throw new ArgumentNullException(nameof(list));
            public int Count => _list.Count;
            public T this[int index] => _list[index];
        }
        sealed class ReadOnlyList<T> : IListLike<T>
        {
            readonly IReadOnlyList<T> _list;
            public ReadOnlyList(IReadOnlyList<T> list) => _list = list ?? throw new ArgumentNullException(nameof(list));
            public int Count => _list.Count;
            public T this[int index] => _list[index];
        }
    }
    

    该复制类关键点在IList<T> list => new List<T>(list),重新new 了一个List。

    本文作者:wwmin
    微信公众号: DotNet技术说
    本文链接:https://www.jianshu.com/p/c2c2b548bec8
    关于博主:评论和私信会在第一时间回复。或者[直接私信]我。
    版权声明:转载请注明出处!
    声援博主:如果您觉得文章对您有帮助,关注点赞, 您的鼓励是博主的最大动力!

    相关文章

      网友评论

          本文标题:c# MoreLinq 之 AggregateRight

          本文链接:https://www.haomeiwen.com/subject/tnijfltx.html