我有如下所述的对象列表:
List<Maths> mObjs = new List<Maths>();
mObjs.Add(new Maths{ Name = "Jack", M1 = 10, M2 = 5, M3 = 0, M4 = 2, M5 =1 });
mObjs.Add(new Maths { Name = "Jill", M1 = 2, M2 = 3, M3 = 4, M4 = 1, M5 = 0 });
mObjs.Add(new Maths { Name = "Michel", M1 = 12, M2 = 15, M3 = 10, M4 = 12, M5 = 11 });
现在我需要计算所有三个人的总聚合值。 我需要得到以下结果,可能是一个新的其他类
List<Results> mRes = new List<Results>();
public class Results{
public string Name { get; set; }
public int TotalValue { get; set; }
}
mRes.Name = "M1"
mRes.TotalValue = 24;
mRes.Name = "M2"
mRes.TotalValue = 23;
mRes.Name = "M3"
mRes.TotalValue = 14;
mRes.Name = "M4"
mRes.TotalValue = 15;
mRes.Name = "M5"
mRes.TotalValue = 12;
如何使用linq查询从mObjs获取此数据?我知道我们可以使用for来做,但想知道是否有更好的方法来使用linq查询来获得这个,因为这减少了代码行,我在许多其他地方有类似的要求,并且不想写foreach或fors的数量每一次。
答案 0 :(得分:4)
您可以使用预选列表列出要选择的名称和字段
var lookups = new Dictionary<string,Func<Maths,int>> {
{"M1", x => x.M1 },
{"M2", x => x.M2 },
{"M3", x => x.M3 },
{"M4", x => x.M4 },
{"M5", x => x.M5 },
};
然后你可以简单地做
var mRes = dlookups.Select(x => new Results {
Name= x.Key,
TotalValue = mObjs.Sum(x.Value)
}).ToList();
开始更新*
回应评论
lambda表达式只是从源类到int的函数。
例如
class Sub1 {
string M3 {get;set;}
int M4 {get;set;}
}
class Math2 {
string Name {get;set;}
string M1 {get;set;}
string M2 {get;set;}
Sub1 Sub {get;set;}
}
var lookups = new Dictionary<string,Func<Math2,int>> {
{ "M1", x => int.Parse(x.M1) },
{ "M2", x => int.Parse(x.M2) },
{ "M3", x => int.Parse(x.Sub.M3) },
{ "M4", x => int.Parse(x.Sub.M4} }
};
或者,如果您想要进行一些错误检查,您可以使用函数或嵌入代码。
int GetInt(string source) {
if (source == null) return 0;
int result;
return int.TryParse(source, out result) ? result : 0;
}
var lookups = new Dictionary<string,Func<Math2,int>> {
{ "M1", x => {
int result;
return x == null ? 0 : (int.TryParse(x,out result) ? result : 0);
},
{ "M2", x => GetInt(x) },
{ "M3", x => x.Sub == null ? 0 : GetInt(x.Sub.M3) },
{ "M4", x => x.Sub == null ? 0 : x.Sub.M4}
};
END UPDATED
如果你想更进一步,你可以使用反射来构建查找词典。
这是一个辅助函数,它将为类的所有Integer属性生成查找。
public Dictionary<string,Func<T,int>> GenerateLookups<T>() where T: class {
// This just looks for int properties, you could add your own filter
var properties = typeof(T).GetProperties().Where(pi => pi.PropertyType == typeof(int));
var parameter = Expression.Parameter(typeof(T));
return properties.Select(x => new {
Key = x.Name,
Value = Expression.Lambda<Func<T,int>>(Expression.Property(parameter,x),parameter).Compile()
}).ToDictionary (x => x.Key, x => x.Value);
}
现在你可以这样做:
var mRes=GenerateLookups<Maths>().Select( x => new Results
{
Name = x.Key,
TotalValue = mObjs.Sum(x.Value)
}).ToList();
答案 1 :(得分:1)
不是很聪明但有效且可读:
int m1Total= 0;
int m2Total= 0;
int m3Total= 0;
int m4Total= 0;
int m5Total= 0;
foreach(Maths m in mObjs)
{
m1Total += m.M1;
m2Total += m.M2;
m3Total += m.M3;
m4Total += m.M4;
m5Total += m.M5;
}
List<Results> mRes = new List<Results>
{
new Results{ Name = "M1", TotalValue = m1Total },
new Results{ Name = "M2", TotalValue = m2Total },
new Results{ Name = "M3", TotalValue = m3Total },
new Results{ Name = "M4", TotalValue = m4Total },
new Results{ Name = "M5", TotalValue = m5Total },
};
结果:
Name: "M1" TotalValue: 24
Name: "M2" TotalValue: 23
Name: "M3" TotalValue: 14
Name: "M4" TotalValue: 15
Name: "M5" TotalValue: 12
编辑:既然您明确要求LINQ,如果属性总是这五个,我不明白为什么你需要使用LINQ。如果数字可以改变,我将使用不同的结构。
您可以使用
List<Measurement>
而不是多个属性,其中Measurement
是另一个存储名称和值的类,或者您可以使用Dictionary<string, int>
,用于高效查找。答案 2 :(得分:0)
你可以试试这样的事情:
mRes.Add(new Results() { Name = "M1", TotalValue = mObjs.Sum(x => x.M1) });
要以编程方式迭代所有类属性,您可能需要使用反射。