C# - 通过与第二个DataTable和第三个DataTable进行比较,从一个DataTable复制行

时间:2018-04-15 17:55:06

标签: c# linq

我的C#代码中有4个DataTables;

DataTable dt1;
DataTable dt2;
DataTable dt3;
DataTable dt4;

dt1有以下记录

Id | Name | City
----------------
1 | Abc | Khi
2 | XYZ | Hyd
3 | TVW | Lhr
4 | tyz | Isb

dt2只有ID记录

Id
---
2
4

我只需要复制dt1dt2dt3中可用的行。还需要在第4 dt4

条中存储不匹配的记录

我发现了这一点,但不知道如何正确地复制到datatable以及not equals如何在这里工作

var matchingRows = from s1 in dt1.AsEnumerable()
                               join s2 in d2.AsEnumerable() on s1.Field<int>("Id") equals s2.Field<int>("Id")
                               select s1;

2 个答案:

答案 0 :(得分:2)

我不喜欢在没有必要时使用var。你正在忽视你实际在做什么。 mathcingRows是一个List。所以任务很简单:

           List<DataRow> matchingRows = (from s1 in dt1.AsEnumerable()
                                          join s2 in dt2.AsEnumerable() on s1.Field<int>("Id") equals s2.Field<int>("Id")
                                          select s1).ToList();
            foreach (DataRow row in matchingRows)
            {
                dt4.Rows.Add(row);
            }

答案 1 :(得分:2)

您可以创建两个查询来查找匹配和不匹配的行,然后将行复制到每个答案DataTable中:

var dt3 = dt1.Clone();
var dt4 = dt1.Clone();

var matchingRows = from s1 in dt1.AsEnumerable()
                   join s2 in dt2.AsEnumerable() on s1.Field<int>("Id") equals s2.Field<int>("Id")
                   select s1;

matchingRows.CopyToDataTable(dt3, LoadOption.OverwriteChanges);

var nonMatchingRows = from s1 in dt1.AsEnumerable()
                      where !dt2.AsEnumerable().Any(s2 => s2.Field<int>("Id") == s1.Field<int>("Id"))
                      select s1;

nonMatchingRows.CopyToDataTable(dt4, LoadOption.OverwriteChanges);

如果dt2包含大量条目且性能比内存更重要,则可以将dt2转换为HashSet以优化匹配测试:

var dt2hs = new HashSet<int>(dt2.AsEnumerable().Select(r => r.Field<int>("Id")));

var matchingRows = from s1 in dt1.AsEnumerable()
                   where dt2hs.Contains(s1.Field<int>("Id"))
                   select s1;

var nonMatchingRows = from s1 in dt1.AsEnumerable()
                      where !dt2hs.Contains(s1.Field<int>("Id"))
                      select s1;

另一个性能选项是只扫描dt1一次,然后手动循环并选择每个目的地:

var dt1jdt2 = from s1 in dt1.AsEnumerable()
              join s2 in dt2.AsEnumerable() on s1.Field<int>("Id") equals s2.Field<int>("Id") into s2j
              from s2 in s2j.DefaultIfEmpty()
              select new { s1, s2 };

foreach (var r in dt1jdt2) {
    if (r.s2 != null)
        dt3.Rows.Add(r.s1.ItemArray);
    else
        dt4.Rows.Add(r.s1.ItemArray);
}

当然,您可以将HashSet和单次扫描选项结合使用:

var dt2hs = new HashSet<int>(dt2.AsEnumerable().Select(r => r.Field<int>("Id")));

foreach (var s1 in dt1.AsEnumerable())
    if (dt2hs.Contains(s1.Field<int>("Id")))
        dt3.Rows.Add(s1.ItemArray);
    else
        dt4.Rows.Add(s1.ItemArray);