C# 将动态匿名对象添加到linq groupBy表达式中
我有以下linq表达式:C# 将动态匿名对象添加到linq groupBy表达式中,c#,linq,C#,Linq,我有以下linq表达式: Func<Entity, object> groupQuery = item => new { a = item.Attributes["name"], item = item.Attributes["number"] }; var result = target.Collection.Entities.GroupBy(groupQuery).ToList(); Func groupQuery=item=> 新的{a=item.Attri
Func<Entity, object> groupQuery = item =>
new { a = item.Attributes["name"], item = item.Attributes["number"] };
var result = target.Collection.Entities.GroupBy(groupQuery).ToList();
Func groupQuery=item=>
新的{a=item.Attributes[“name”],item=item.Attributes[“number”]};
var result=target.Collection.Entities.GroupBy(groupQuery.ToList();
但若我不知道要分组多少列(例如3而不是2),以及列表名称中存储的属性名称,那个么我应该如何更改groupQuery对象?我的第一个想法是创建这样的动态对象,但它不起作用
dynamic groupQuery= new ExpandoObject();
IDictionary<string, object> dictionary = (IDictionary<string, object>)groupQuery;
foreach (string str in Names)
{
dictionary.Add(str, str);
}
dynamicgroupquery=newexpandoobject();
IDictionary dictionary=(IDictionary)组查询;
foreach(名称中的字符串str)
{
添加(str,str);
}
您可以返回字符串,而不是从groupQuery返回对象。此字符串将根据要分组的对象的属性构造。根据配置的不同,它可以以不同的方式生成,即基于不同的属性。下面是一段代码,显示了一个想法:
public class A
{
public string Property1 { get; set; }
public string Property2 { get; set; }
public string Property3 { get; set; }
}
public enum GroupByuMode
{
GroupBy1,
GroupBy2,
GroupBy3,
}
...
var list = new List<A>();
for (int i = 0; i < 10; ++i)
for (int j = 0; j < 10; ++j)
for (int k = 0; k < 10; ++k)
list.Add(new A { Property1 = i.ToString(), Property2 = j.ToString(), Property3 = k.ToString() });
var mode = GroupByuMode.GroupBy1;
Func<A, object> func = a =>
{
if (mode == GroupByuMode.GroupBy1)
return a.Property1;
else if (mode == GroupByuMode.GroupBy2)
return String.Format("{0}_{1}", a.Property1, a.Property2);
else if (mode == GroupByuMode.GroupBy3)
return String.Format("{0}_{1}_{2}", a.Property1, a.Property2, a.Property3);
return null;
};
var res = list.GroupBy(func).ToList();
Console.WriteLine(res.Count);
mode = GroupByuMode.GroupBy2;
res = list.GroupBy(func).ToList();
Console.WriteLine(res.Count);
公共A类
{
公共字符串属性1{get;set;}
公共字符串属性2{get;set;}
公共字符串属性3{get;set;}
}
公共枚举GroupByuMode
{
GroupBy1,
GroupBy2,
GroupBy3,
}
...
var list=新列表();
对于(int i=0;i<10;++i)
对于(int j=0;j<10;++j)
对于(int k=0;k<10;++k)
添加(新的A{Property1=i.ToString(),Property2=j.ToString(),Property3=k.ToString()});
var mode=GroupByuMode.GroupBy1;
Func Func=a=>
{
if(mode==GroupByuMode.GroupBy1)
返回a.Property1;
else if(mode==GroupByuMode.GroupBy2)
返回String.Format(“{0}{1}”,a.Property1,a.Property2);
else if(mode==GroupByuMode.GroupBy3)
返回String.Format(“{0}{1}{2}”,a.Property1,a.Property2,a.Property3);
返回null;
};
var res=list.GroupBy(func.ToList();
控制台写入线(res.Count);
mode=GroupByuMode.GroupBy2;
res=list.GroupBy(func.ToList();
控制台写入线(res.Count);
如上图所示,它对对象起作用。您必须检查它是否与LINQ to实体或LINQ的另一个实现一起工作。回答问题
IEnumerable columnsToGroupBy=new[]{Names.First()};
名称。删除(0);
聚合(columnsToGroupBy,(current,query)=>current.Concat(new[]{query}));
GroupQuery=r=>newntuple(从列中的列到groupby选择r[column]);
///////
使用制度;
使用System.Collections.Generic;
使用System.Linq;
命名空间WBTCB.AggregationService.Models.Helpers
{
公共类N倍:I相等
{
公共N元组(IEnumerable值)
{
Values=Values.ToArray();
}
公共只读T[]值;
公共覆盖布尔等于(对象对象对象)
{
if(ReferenceEquals(this,obj))
返回true;
if(obj==null)
返回false;
返回等于(obj为N倍);
}
公共布尔等于(其他的N倍)
{
if(ReferenceEquals(this,other))
返回true;
如果(其他==null)
返回false;
变量长度=值。长度;
if(长度!=其他.Values.length)
返回false;
对于(变量i=0;icurrent*37+(!ReferenceEquals(value,null)?value.GetHashCode():0));
}
}
}
通用算法最适合未知/无限的可能性。。我敢打赌,如果你仔细考虑,你会发现你有大约50种不同的可能性。。最好将每个实现(groupQuery)具体存储在一个字典中,并用一个键(半自动)调用它,“但是如果我不知道,我将分组多少列(例如3而不是2),以及存储在列表名中的属性名”那么你知道什么?一定有什么你知道的,对吧?例如,要按或分组的属性名称列表?您可以使用其预定义的,而不是动态=(但感谢您的回答)
IEnumerable<string> columnsToGroupBy = new[] { Names.First()};
Names.RemoveAt(0);
Names.Aggregate(columnsToGroupBy, (current, query) => current.Concat(new[] {query}));
GroupQuery = r => new NTuple<object>(from column in columnsToGroupBy select r[column]);
///////
using System;
using System.Collections.Generic;
using System.Linq;
namespace WBTCB.AggregationService.Models.Helpers
{
public class NTuple<T> : IEquatable<NTuple<T>>
{
public NTuple(IEnumerable<T> values)
{
Values = values.ToArray();
}
public readonly T[] Values;
public override bool Equals(object obj)
{
if (ReferenceEquals(this, obj))
return true;
if (obj == null)
return false;
return Equals(obj as NTuple<T>);
}
public bool Equals(NTuple<T> other)
{
if (ReferenceEquals(this, other))
return true;
if (other == null)
return false;
var length = Values.Length;
if (length != other.Values.Length)
return false;
for (var i = 0; i < length; ++i)
if (!Equals(Values[i], other.Values[i]))
return false;
return true;
}
public override int GetHashCode()
{
return Values.Aggregate(17, (current, value) => current*37 + (!ReferenceEquals(value, null) ? value.GetHashCode() : 0));
}
}
}