惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Apple Machine Learning Research
Apple Machine Learning Research
博客园 - 三生石上(FineUI控件)
雷峰网
雷峰网
WordPress大学
WordPress大学
S
SegmentFault 最新的问题
博客园 - 叶小钗
The Cloudflare Blog
T
Tailwind CSS Blog
Hugging Face - Blog
Hugging Face - Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
月光博客
月光博客
小众软件
小众软件
罗磊的独立博客
酷 壳 – CoolShell
酷 壳 – CoolShell
大猫的无限游戏
大猫的无限游戏
阮一峰的网络日志
阮一峰的网络日志
V
V2EX
美团技术团队
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 聂微东
量子位
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
宝玉的分享
宝玉的分享

博客园 - Zhenway

Azure SignalR支持replication啦 Azure SignalR总览 定制json序列化 今天折腾这么一个正则 docfx组件介绍--YamlSerialization docfx daylybuild docfx开源啦 docfx组件介绍--MarkdownLite docfx预热中 合并批量请求 在finally中调用一个需要await的方法 当泛型方法推断,扩展方法遇到泛型类型in/out时。。。 4.5你太黑了,不带这么玩TypeForwardedTo的 一个非常简单的反射加速方案 加载时预防并发执行 又发现一个msdn的坑 又发现个.net framework的坑 sql server死锁神器 踩到一个Emit的坑,留个纪念
一个简单的Linq to TreeNode
Zhenway · 2014-10-22 · via 博客园 - Zhenway

  最近两天写单元测试,碰到需要验证一个树是否是期望的,但是树这个结构要验证起来还真是有点烦。。。

  我的树大概是这样的:

 1 class TreeNode<T>
 2 {
 3         private static readonly TreeNode<T>[] Empty = new TreeNode<T>[0];
 4         public TreeNode() : this(default(T), Empty) { }
 5         public TreeNode(T value, IReadOnlyList<TreeNode<T>> children)
 6         {
 7             Value = value;
 8             Children = children;
 9         }
10         public T Value { get; set; }
11         public IReadOnlyList<TreeNode<T>> Children { get; set; }
12 }

View Code

  为了判等,这个树实现了IEquatable<TreeNode<T>>接口:

 1         public override bool Equals(object obj)
 2         {
 3             var other = obj as TreeNode<T>;
 4             if (other == null)
 5             {
 6                 return false;
 7             }
 8             return Equals(other);
 9         }
10 
11         public bool Equals(TreeNode<T> other)
12         {
13             return object.Equals(Value, other.Value) && Children.SequenceEqual(other.Children);
14         }
15 
16         public override int GetHashCode()
17         {
18             return Value.GetHashCode() ^ Children.Aggregate(Children.Count, (seed, x) => seed ^ x.GetHashCode());
19         }

View Code

  看着还不错,不过由于T实际是个复杂类型,每次重写Equals也是个不轻松的事情,而且还要把整个期望的树给构造出来,呵呵,还是烦啊。。。

  但是,如果只需要判定个把简单属性,事情就方便了许多,所以,TreeNode需要一个方法来转换T的类型:

1         public TreeNode<TResult> Select<TResult>(Func<T, TResult> selector)
2         {
3             return new TreeNode<TResult>(selector(Value), (from c in Children select c.Select(selector)).ToList());
4         }

View Code

  看起来不错,这样就可以有这样的code来玩转tree了:

1 TreeNode<int> intTree = ...
2 TreeNode<string> stringTree = intTree.Select(i => i.ToString());

View Code

  等等,我们可以把这代码写的跟linq:

1 TreeNode<int> intTree = ...
2 TreeNode<string> stringTree = from i in intTree
3                               select i.ToString();

View Code

  测试代码继续啪啦啪啦的写,唉,测试失败了,什么情况,仔细一看,哦,tree下面节点的顺序错了,而tree的equals方法要求顺序,但是这个测试刚好不要求顺序,于是我有了两个选择:

1. 改写equals方法 (不想折腾集合操作)

2. 让节点排序 (对测试用例而言,构建一个有顺序的树可是很简单的事情)

  所以,我需要个OrderBy:

1         public TreeNode<T> OrderBy<TKey>(Func<T, TKey> keySelector)
2         {
3             return new TreeNode<T>(Value, (from c in Children
4                                            orderby keySelector(c.Value)
5                                            select c.OrderBy(keySelector)).ToList());
6         }

View Code

  这下就可以随便折腾这个树了:

1 TreeNode<int> intTree = ...
2 TreeNode<string> stringTree = from i in intTree
3                               let m = i % 3
4                               order by m
5                               select i.ToString();

View Code