发一个GroupBy动态选择多列的代码

threenewbee 2018-11-22 12:51:36
加精
LINQ的GroupBy需要传入一个keyselector的Lambda表达式,但是如果需要分组的条件不确定,需要通过程序输入判断,就比较麻烦了。
以前写过一个动态分组的代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;

namespace DynamicGroupBy
{
static class LinqExt
{
public class DGroupBy<T> : IGrouping<object[], T>
{
private List<T> _innerlist = new List<T>();

private object[] _key;

public DGroupBy(object[] key) { _key = key; }

public object[] Key
{
get { return _key; }
}

public void Add(T value)
{
_innerlist.Add(value);
}

public IEnumerator<T> GetEnumerator()
{
return this._innerlist.GetEnumerator();
}

System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this._innerlist.GetEnumerator();
}
}

public static IEnumerable<IGrouping<object[], T>> DynamicGroupBy<T>(this IEnumerable<T> data, string[] keys)
{
List<DGroupBy<T>> list = new List<DGroupBy<T>>();

var exps = keys.Select(x =>
{
var para = Expression.Parameter(typeof(T), "p");
Expression<Func<T, object>> GetProp = Expression.Lambda<Func<T, object>>(
Expression.MakeMemberAccess(para, typeof(T).GetProperty(x)), para) as Expression<Func<T, object>>;
return GetProp.Compile();
}).ToArray();

foreach (var item in data.Select(x => new {
k = exps.Select(y => y(x)).ToArray(),
v = x
}))
{
DGroupBy<T> existing = list.SingleOrDefault(x => x.Key.Zip(item.k, (a, b) => a.Equals(b)).All(y => y));
if (existing == null)
{
existing = new DGroupBy<T>(item.k);
list.Add(existing);
}
existing.Add(item.v);
}
return list;
}
}

class User
{
public int ID { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public string City { get; set; }
public override string ToString()
{
return string.Format("{0},{1},{2},{3}", ID, Name, Age ,City);
}
}

class Program
{
static void Main(string[] args)
{
List<User> users = new List<User>()
{
new User() { ID = 1, Age = 20, City = "BJ", Name = "A" },
new User() { ID = 2, Age = 20, City = "BJ", Name = "B" },
new User() { ID = 3, Age = 20, City = "BJ", Name = "C" },
new User() { ID = 4, Age = 20, City = "SH", Name = "D" },
new User() { ID = 5, Age = 30, City = "SH", Name = "E" },
new User() { ID = 6, Age = 30, City = "SH", Name = "F" },
new User() { ID = 7, Age = 30, City = "CD", Name = "G" },
new User() { ID = 8, Age = 30, City = "CD", Name = "H" },
new User() { ID = 9, Age = 30, City = "HK", Name = "I" },
new User() { ID = 10, Age = 30, City = "HK", Name = "J" },
};
var query = users.DynamicGroupBy(new string[] { "City" });
foreach (var item in query)
{
Console.WriteLine("Key: {0}", string.Join(",", item.Key.Select(x => x.ToString())));
foreach (var item1 in item)
Console.WriteLine("\t" + item1);
}
}
}
}


因为用了一些反射,效率我觉得比较低,原因是动态创建selector对象比较麻烦,后来想了想,其实不需要这么做,多次调用 GroupBy 分别按照多个字段分组,最后再Select下,把Key合并就可以了。
...全文
5269 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
onOneLight 2018-12-10
  • 打赏
  • 举报
回复
clever_yang 2018-12-05
  • 打赏
  • 举报
回复
,不错,不错~~
qzyf1992 2018-12-04
  • 打赏
  • 举报
回复
group by传age报错哈
邓壮 2018-12-04
  • 打赏
  • 举报
回复
非常好的帖子哦,赞赞赞
  • 打赏
  • 举报
回复
所以这是???
良朋 2018-11-26
  • 打赏
  • 举报
回复
收藏收藏收藏收藏
啊宝儿姐 2018-11-23
  • 打赏
  • 举报
回复
所以。。。。斑竹发现新大陆了
peng2739956 2018-11-22
  • 打赏
  • 举报
回复
所以,大版主,你这贴 是想说 以前想的太多了?

7,765

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 非技术区
社区管理员
  • 非技术区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧