C# 实现groupby动态分组

1 篇文章 0 订阅
以学生类为例
public class Student
{  
    public string Name { get; set; }  
    public int Age { get; set; }  
    public string Gender { get; set; }  
}

一、单条件

利用表达式Expression实现动态单条件分组(成功)

//用来作分组条件的字段
string groupCondition = "Gender";
//生成e的指向
var parameter = Expression.Parameter(typeof(Student), "e");
//根据groupCondition分组 生成e.Gender
var propertyReference = Expression.Property(parameter, groupCondition);
//生成Lambda表达式
var func = Expression.Lambda<Func<Student, object>>(propertyReference, new[] { parameter }).Compile();
//执行分组 where用来筛选出组内数据大于一条的组
var allUnique = students.GroupBy(func).Where(o => o.Count() > 1).Select(c => c.ToList());

二、多条件

1.直接使用三目运算符来判断哪些字段需要用于分组(成功)

//groupby会自动忽略空字符串""
var allUnique = students.GroupBy(e => new
{
     Gender = 判断条件1 ? "" : e.Gender,
     Name= 判断条件2 ? "" : e.Name,
     Age = 判断条件3 ? "" : e.Age,
}).Where(o => o.Count() > 1).Select(c => c.ToList());

2.利用IGrouping接口实现分组(成功)

string conditionString = "Gender,Name,Age"
//用字符串数组存储分组条件
string[] conditionArray = conditionString.Split(new char[] { ',', ',' });
List<DGroupBy<T>> result= new List<DGroupBy<T>>();
var itemList = sendRequests.Select(u => new
{
     key = keys.Select(p =>
     {
         var property = u.GetType().GetProperty(p);
         if (property != null)
         {
             return property.GetValue(u, null);
         }
         else
         {//未获取到属性
              return "";
         }
      }).ToArray(),
      value = u
});
//分组条件conditionArray,需要分组的数据students,分组结果list
foreach (var item in itemList)
{
    DGroupBy<T> existing = result.SingleOrDefault(u => u.Key.Zip(item.key, (a, b) => a.Equals(b)).All(p => p));
    if (existing == null)
    {
        existing = new DGroupBy<T>(item.key);
        result.Add(existing);
    }
    existing.Add(item.value);
}
  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();
      }
  }

3.利用ExpressionTree表达式树实现(探索中) 

var source = typeof(Student);
var e = Expression.Parameter(source,"e");
//e.Gender
var sourceGender = Expression.MakeMemberAccess(e, source.GetProperty("Gender"));
//e.Age
var sourceAge = Expression.MakeMemberAccess(e, source.GetProperty("Age"));
//Gender = e.Gender
var assignGender = Expression.Bind(source.GetProperty("Gender"), sourceGender);
//Age => e.Age
var assignAge = Expression.Bind(source.GetProperty("Age"), sourceAge);
var target = Expression.New(typeof(Student));
// e=> new Student(){Gender = e.Gender,Age = e.Age}
var init = Expression.MemberInit(target, assignGender, assignAge);
var func = Expression.Lambda<Func<Student, object>>(init, e).Compile();
var allUnique = students.GroupBy(func).Where(o => o.Count() > 1).Select(c => c.ToList());

问题在于利用Expression表达式树生成的lambda必须指明类型,无法生成匿名类型,groupby需要匿名类型的分组条件,不然就得重写GetHashCode和Equal方法,我不想改动类就没有重写。或者可以尝试自己写一个比较器,传给groupby。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值