C# 使用linq将多个和合并为一个匿名类型?
我有一个简单的数据表:C# 使用linq将多个和合并为一个匿名类型?,c#,.net,linq,datatable,C#,.net,Linq,Datatable,我有一个简单的数据表: type (string) | cnt (int) _____________________________________ aaa 1 aaa 2 aaa 10 bbb 1 bbb 1 我想生成如下的1
type (string) | cnt (int)
_____________________________________
aaa 1
aaa 2
aaa 10
bbb 1
bbb 1
我想生成如下的1匿名类型:
{
sumAAA= 13 , sumBBB=2 //13=1+2+10....
}
类似:(psuedo代码)
有什么帮助吗
编辑,这将帮助您
DataTable dt = new DataTable("myTable");
dt.Columns.Add("cnt", typeof (int));
dt.Columns.Add("type", typeof (string));
DataRow row = dt.NewRow();
row["cnt"] = 1;
row["type"] = "aaa";
dt.Rows.Add(row);
row = dt.NewRow();
row["cnt"] = 2;
row["type"] = "aaa";
dt.Rows.Add(row);
row = dt.NewRow();
row["cnt"] = 10;
row["type"] = "aaa";
dt.Rows.Add(row);
row = dt.NewRow();
row["cnt"] = 1;
row["type"] = "bbb";
dt.Rows.Add(row);
row = dt.NewRow();
row["cnt"] = 1;
row["type"] = "bbb";
dt.Rows.Add(row);
这将给你一个匿名{type,sum}列表,这一定是一个好的开始 有什么理由不想使用2条LINQ语句吗
var obj = new {
sumAAA = dt.Rows
.Where(x => x["type"] == "aaa")
.Sum(y => (int) y["cnt"]),
sumBBB = dt.Rows
.Where(x => x["type"] == "bbb")
.Sum(y => (int) y["cnt"])
};
还是一个简单的for循环
int sAAA = 0; int sBBB = 0;
foreach (DataRow row in dt.Rows)
{
if(row["type"] == "aaa")
sAAA += (int) row["cnt"];
else
sBBB += (int) row["cnt"];
}
var obj = new { sumAAA = sAAA, sumBBB = sBBB };
编辑:哦。。。匿名对象是不可变的,因此相应地更改了我的答案在程序集中,具有相同属性且具有相同类型和顺序的所有匿名类型都是相同的类型。因此,可以创建相同匿名类型的新实例: 第一版 但总的来说,我们可以做得更好 第二版 更新:使用版本2的完整示例 (使用元组是因为它们更容易设置): 粘贴到默认的C#控制台项目中:
using System;
using System.Linq;
class Program {
static void Main(string[] args) {
var input = Enumerable.Range(1, 10).Select(x => Tuple.Create(x, x*x));
var res = input.Aggregate(new { Firsts = 0, Seconds = 0}, (total, val) => {
return new {
Firsts = total.Firsts + val.Item1,
Seconds = total.Seconds + val.Item2
};
});
Console.WriteLine("Firsts: {0}; Seconds: {1}", res.Firsts, res.Seconds);
}
}
充满活力:
dynamic result = new ExpandoObject();
dt.AsEnumerable()
.GroupBy(r => r.Field<String>("type"))
.ToList()
.ForEach(g=> ((IDictionary<String, Object>)result)["sum" + g.Key.ToUpper()] = g.Sum(r=>r.Field<Int32>("cnt")));
Console.WriteLine(result.sumAAA);
Console.WriteLine(result.sumBBB);
dynamic result=new expandooobject();
dt.AsEnumerable()
.GroupBy(r=>r.Field(“类型”))
托利斯先生()
.ForEach(g=>((IDictionary)结果)[“sum”+g.Key.ToUpper()]=g.sum(r=>r.Field(“cnt”));
Console.WriteLine(result.sumAAA);
Console.WriteLine(result.sumbbbb);
适用于任意数量的不同类型
s,不仅适用于aaa
和bbb
输出:
dynamic result = new ExpandoObject();
dt.AsEnumerable()
.GroupBy(r => r.Field<String>("type"))
.ToList()
.ForEach(g=> ((IDictionary<String, Object>)result)["sum" + g.Key.ToUpper()] = g.Sum(r=>r.Field<Int32>("cnt")));
Console.WriteLine(result.sumAAA);
Console.WriteLine(result.sumBBB);
13二,
您希望将行转换为属性,本质上是对数据的模式进行非规范化或转置?是否将
bb
与bbb
?@Jodrell其也是bbb求和。固定的。谢谢。你可以按照Scorpi0的答案对数据进行分组,但是你必须动态地创建一个匿名类型,这对编码没有多大好处,请看这个问题。除非您知道编译时数据中会出现哪些组?@Jodrell我只想要一个包含两个和的对象。我不想使用任何循环。我想要一个同时包含两个结果的匿名类型。@Royi Namir,这是您最初要求的,但不需要将所有类型检查推到运行时,因此可能非常“不好”。然而,这是一个很好的答案。为什么不用javascript写这个呢。r.Field(“type”)不是很像r[“type”]。ToString()
?@Royi不完全一样Field
将值强制转换为String
,而ToString()
是对ToString()
的调用Field
它还将DBNull
转换为null
@BigYellowCactus如何从expando安全地获取属性,但要先检查属性是否存在?如果我尝试myExpando.NoitExists,你会怎么做?它不会爆炸吗?@RoyiNamir使用或只是将ExpandoObject
强制转换为IDictionay
,然后使用或。这个版本2看起来不错,但是。。。它简直无法编译!原因是类型检查器无法统一两个相似的匿名类-1.@EartEngine:刚刚在这里测试过(使用元组而不是数据表作为输入,设置起来更容易):没问题。该方法确实依赖于匿名类型的初始和增量定义,匿名类型具有相同的名称和相同顺序的类型(例如,如果输入内容为double
请确保使用double创建初始值)。我将在答案中添加测试代码。@Richard这似乎是C#编译器版本的问题。在Visual studio 2010中,这是一个错误,而在MonoDevelop 4.0.12中则不是(并且似乎假定具有相同字段的匿名类型是相同的)。因此,您可能需要更新您的答案。@EartEngine:它可能很容易依赖于版本,但不必花时间研究决定它的IDE、BCL或语言功能,我宁愿关注工具的当前版本(可能是以前的版本)。(旧版本:创建并使用命名结构,可以是包含类的私有成员。)
var result2 = dt.AsEnumerable().Aggregate(new { SumAs = 0, SumBs = 0 }, (total, dr) => {
return new {
SumAs = total.SumAs + (dr["type"].Equals("aaa") ? (int)dr["cnt"] : 0),
SumBs = total.SumBs + (dr["type"].Equals("bbb") ? (int)dr["cnt"] : 0)
};
});
using System;
using System.Linq;
class Program {
static void Main(string[] args) {
var input = Enumerable.Range(1, 10).Select(x => Tuple.Create(x, x*x));
var res = input.Aggregate(new { Firsts = 0, Seconds = 0}, (total, val) => {
return new {
Firsts = total.Firsts + val.Item1,
Seconds = total.Seconds + val.Item2
};
});
Console.WriteLine("Firsts: {0}; Seconds: {1}", res.Firsts, res.Seconds);
}
}
dynamic result = new ExpandoObject();
dt.AsEnumerable()
.GroupBy(r => r.Field<String>("type"))
.ToList()
.ForEach(g=> ((IDictionary<String, Object>)result)["sum" + g.Key.ToUpper()] = g.Sum(r=>r.Field<Int32>("cnt")));
Console.WriteLine(result.sumAAA);
Console.WriteLine(result.sumBBB);