65.9K
CodeProject 正在变化。 阅读更多。
Home

一个 C# 扩展方法,用于递归选择所有后代

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.85/5 (11投票s)

2017 年 3 月 8 日

CPOL
viewsIcon

24398

如何使用扩展方法递归选择所有后代

引言

.NET 的 SelectMany 扩展方法仅选择源的直接子项。在这里,我提供两个名为 SelectManyRecursiveSelectManyAllInclusiveIEnumerable<T> 扩展方法第一个将仅选择后代,而第二个将选择后代源集合中的项目。我还包含一个测试程序来演示其工作原理。

Using the Code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
 
namespace SelectManyRecursive
{
    public static class Extensions
    {
        public static IEnumerable<T> SelectManyRecursive<T>
                (this IEnumerable<T> source, Func<T, IEnumerable<T>> selector)
        {
            var result = source.SelectMany(selector);
            if (!result.Any())
            {
                return result;
            }
            return result.Concat(result.SelectManyRecursive(selector));
        }
 
        public static IEnumerable<T> SelectManyAllInclusive<T>
               (this IEnumerable<T> source, Func<T, IEnumerable<T>> selector)
        {
            return source.Concat(source.SelectManyRecursive(selector));
        }
    }
 
    class Test
    {
        int _level;
        public List<Test> Children = new List<Test>();
 
        static Random rand = new Random(DateTime.Now.Millisecond);
        public static int maxLevels = 5;
        public static int total = 0;
 
        public Test() : this(1)
        {
        }
 
        private Test(int level)
        {
            ++total;
            _level = level;
            if (level < maxLevels)
            {
                int numChildren = rand.Next(10) + 1;
                ++level;
                while (numChildren-- > 0)
                {
                    Children.Add(new Test(level));
                }
            }
        }
    }
 
    class Program
    {
        static void Main(string[] args)
        {
            List<Test> root = new List<Test> { new Test(), new Test() };
            var descendents = root.SelectManyRecursive(t => t.Children);
            int descendantsCount = descendents.Count();
 
            var all = root.SelectManyAllInclusive(t => t.Children);
            var count = all.Count();
 
            Console.WriteLine($@"Total Test instances = {Test.total}
Total descendents collected = {descendantsCount}.
 
Note that 'Total descendents' will correctly be {root.Count} less than
'Total Test instances' because SelectManyRecursive selects only the descendents.
 
SelectManyAllInclusive (count = {count}) will select all items including from the source.
 
Press enter to continue:");
            Console.Read();
        }
    }
}

关注点

存在比此处介绍的算法更高效的非递归算法。

历史

  • 2017 年 3 月 8 日:第一个版本
  • 2017 年 3 月 9 日:更改为使用 result.Any() 代替 .ToList() 和 .Count,因为 .ToList() 可能会导致不必要的开销。
一个 C# 扩展方法,用于递归选择所有后代 - CodeProject - 代码之家
© . All rights reserved.