这应该很简单,但我无法弄清楚。我有一个数据表,其中包含姓名,年龄,其中有行具有学生姓名,但随后是多行特殊学生的姓名"克里斯"和约翰的。最终结果应该有一个表格,其中包含除 Chris 和 John 之外的所有行,以合并为一行,称为"其他",并附有他们的年龄总和。
即。
NAME | AGE
Tom | 20
John | 15
Peter | 5
John | 2
Tom | 33
Chris | 20
最终结果:
NAME | AGE
Tom | 20
Peter | 5
Tom | 33
Other | 37
这就是我现在正在做的事情:
var others = table.AsEnumerable().Where(x => x["NAME"].ToString().Equals("Chris") || x["NAME"].ToString().Equals("John"));
var tmpOthers = 0;
foreach (DataRow otherRow in others)
tmpOthers += decimal.Parse(otherRow["AGE"].ToString());
table = table.AsEnumerable().Where(x => !x["NAME"].ToString().Equals("Chris") || !x["NAME"].ToString().Equals("John")).CopyToDataTable();
table.Add(//OTHER-ROW-Here)
这有效,但我知道在单个 LiNQ 语句中必须有一种更简单的方法可以做到这一点。 我也不能放桌子。Rows.Remove 在相同的 for 循环中,因为迭代更改。
我会使用 Linq + delegate 来做到这一点。为什么?对于这种情况,带有委托的解决方案更优雅、更具体,因为名称可能以大字母或小字母开头。检查以下解决方案:
//delegate to return "Other" for {"Chris","John"} - ignoring case
Func<string, string> GetOtherName = delegate(string s)
{
if(string.Equals(s, "Chris", StringComparison.OrdinalIgnoreCase) ||
string.Equals(s, "John", StringComparison.OrdinalIgnoreCase))
return "Other";
else
return s;
};
//get total age for "Other"
var otherAge = dt.AsEnumerable()
.Where(x=>GetOtherName(x.Field<string>("NAME")) == "Other")
.Select(x=>x.Field<int>("AGE")).Sum();
//remove "Other" rows
dt.AsEnumerable()
.Where(x=>GetOtherName(x.Field<string>("NAME")) == "Other")
.ToList()
.ForEach(r=>r.Delete());
//finally add "other" row
dt.Rows.Add(new object[]{"Other", otherAge});
结果:
NAME AGE
Tom 20
Peter 5
Tom 33
Other 37
有关更多详细信息,请参阅: Func 代表
好吧,您可以使用for
循环来实现此目的,例如
for(int i=0; i<others.Count(); i++)
table.Rows.Remove(others[i]);