public class EstimateModel { public int ShopID { get; set; } //key: 年份 public Dictionary<string, List<TagCrowdFilterModel>> YearCrowdFilterDict { get; set; } } public class TagCrowdFilterModel { /// <summary> /// 筛选条件 /// </summary> public string CrowdFiter { get; set; } /// <summary> /// 获取人数 /// </summary> public int TotalCustomerCount { get; set; } }
为了更加清晰,我决定再添补一下数据
public static void Main(string[] args) { var estimateModel = new EstimateModel() { ShopID = 1, YearCrowdFilterDict = new Dictionary<string, List<TagCrowdFilterModel>>() { { "17年",new List<TagCrowdFilterModel>() { new TagCrowdFilterModel(){ CrowdFiter="between 10 and 20" }, new TagCrowdFilterModel(){ CrowdFiter=" a<10 || a>30" }, } }, { "18年",new List<TagCrowdFilterModel>() { new TagCrowdFilterModel(){ CrowdFiter="between 100 and 200" }, new TagCrowdFilterModel(){ CrowdFiter=" a<100 || a>300" }, } }, { "19年",new List<TagCrowdFilterModel>() { new TagCrowdFilterModel(){ CrowdFiter="between 1000 and 2000" }, new TagCrowdFilterModel(){ CrowdFiter=" a<1000 || a>3000" }, } } } }; } public static int GetCustomerID(string crowdfilter) { return BitConverter.ToInt32(Guid.NewGuid().ToByteArray(), 0); }
2. 实现需求
需求也很大略,便是依次获取 TagCrowdFilterModel 中的 CrowdFiter 字段再调用GetCustomerID方法把人数赋值给TotalCustomerCount即可,这么大略的需求,如果让你来搞定,你该怎么实现这个逻辑? 没错,很多人可能便是两个foreach搞定。
foreach (var year in estimateModel.YearCrowdFilterDict.Keys) { var yearCrowdFitlerList = estimateModel.YearCrowdFilterDict[year]; foreach (var crowdFitler in yearCrowdFitlerList) { crowdFitler.TotalCustomerCount = GetCustomerID(crowdFitler.CrowdFiter); } }
看似代码也很清爽,但现实哪有这么好的事情,真实情形是年份上可能还要套上一个客户类型,客户类型之上再套一个商品,商品之上再套一个商家,这样很深的层级你就须要多达3个foreach,4个foreach乃至5个foreach才能搞定,再放张图给大家看看,是不是看着头大...

3. 优化办法
如果你会selectMany,那只须要一个链式写法就可以搞定,是不是大略粗暴,虽然性能比不上命令式写法,但可读性和不雅观赏性真的上了几个档次。
estimateModel.YearCrowdFilterDict.SelectMany(m => m.Value).ToList().ForEach(m => m.TotalCustomerCount = GetCustomerID(m.CrowdFiter) );
二:事理探究1. msdn阐明
将序列的每个元素投影到 IEnumerable,并将结果序列合并为一个序列,并对个中每个元素调用结果选择器函数,链接:https://docs.microsoft.com/zh-cn/dotnet/api/system.linq.enumerable.selectmany?view=netframework-4.8 有了上面的案例阐明,再看msdn的这句话,我想你该当彻彻底底的明白了selectMany怎么利用。
2. 翻查源码宏不雅观上明白了,接下来用ILSpy去查下微不雅观代码,到底这玩意是怎么实现的。
public static IEnumerable<TResult> SelectMany<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TResult>> selector){ if (source == null) { throw Error.ArgumentNull("source"); } if (selector == null) { throw Error.ArgumentNull("selector"); } return SelectManyIterator(source, selector);}private static IEnumerable<TResult> SelectManyIterator<TSource, TResult>(IEnumerable<TSource> source, Func<TSource, IEnumerable<TResult>> selector){ foreach (TSource item in source) { foreach (TResult item2 in selector(item)) { yield return item2; } }}
大家仔细体会下这两个foreach,尤其是第二个foreach,个中的selector(item)不便是年份下的标签凑集吗?再遍历这个凑集把每一个item返回出去,返回值是IEnumerable,这得益于yield语法糖,它实质上便是一个编译器封装好的迭代类,做到了一个延迟,按需实行,后面我会专门分享一下yield,很故意思
好了,本篇就说到这里,希望对你有帮助。