Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/295.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
c#使用LiNQ删除Datatable中的多行_C#_Linq_Datatable - Fatal编程技术网

c#使用LiNQ删除Datatable中的多行

c#使用LiNQ删除Datatable中的多行,c#,linq,datatable,C#,Linq,Datatable,这应该很简单,但我无法理解。我有一个数据表,它有Name,Age,其中有一些行有学生的名字,但有多行特殊学生的名字‘Chris’和‘John’。最终结果应该有一个表,其中包含除Chris和John之外的所有行,并将它们合并为一行,称为Other,其中包含它们的年龄总和 即 最终结果: NAME | AGE Tom | 20 Peter | 5 Tom | 33 Other | 37 这就是我现在正在做的: var others = table.AsEnumerable().Where(x =&

这应该很简单,但我无法理解。我有一个数据表,它有Name,Age,其中有一些行有学生的名字,但有多行特殊学生的名字‘Chris’和‘John’。最终结果应该有一个表,其中包含除Chris和John之外的所有行,并将它们合并为一行,称为Other,其中包含它们的年龄总和

最终结果:

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语句中必须有一种更简单的方法来实现这一点。此外,由于迭代更改,我无法将table.Rows.Remove放在相同的for循环中。

您可以使用
for
循环,如

for(int i=0; i<others.Count(); i++)
    table.Rows.Remove(others[i]);

for(int i=0;i我会使用Linq+delegate。为什么?对于这种情况,带有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});

有关更多详细信息,请参阅:

RemoveRange?名称是否总是以大写开头?它与For循环一起工作,但我给出的代码有点混乱,我知道应该有一种方法将所有逻辑写入一个LiNQ语句。类似于
table.AsEnumerable()。其中(x=>x[“name”]。ToString()。等于(“Chris”)| | x[“NAME”].ToString().Equals(“John”)(用一些局部变量总结年龄)。删除这些行。copytable()
这样的逻辑@civic.sir在我看来,巨型linq语句比您的原始代码更混乱。您可以对.Where()结果集执行.ForEach(),但我不确定如何删除Where()上的更改之后再说一遍。@dckuehn是的,这就是我要找的…ForEach()。然后我可以在哪里做一个copytoDataTable()最后no?@civic.sir我不认为你可以有一个LINQ语句,既可以向列表中添加一个新条目,又可以同时删除实体。即使你可以,我认为这会比你当前的解决方案更混乱。啊,我明白了。kk是有意义的,感谢lotSuper!这太干净了!喜欢这种编码风格
//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