【问题标题】:Find duplicates in datatable with multiple columns except two在数据表中查找除两列外的多列重复项
【发布时间】:2017-02-09 14:02:17
【问题描述】:

我是编码新手并尝试检查电子表格中的重复行。电子表格有 50 列,除两列外,每一列都必须进行比较。如果行重复,则将它们合并为一行,并将 REQNUM 和 AUTHNUM 列中的金额相加。我发现的大多数示例都使用“字段(”列名“)”。由于列的数量很大,我想使用一个变量来排除我在比较中不需要的两个。

示例:
前。点代表更多列
COL1|COL2|COL3|...|REQNUM|AUTHNUM
:-----: | :-----: | :----: |...| :------------: | :-----------: |....
x |是 | z |...| 1 | 1
x |是 | z |...| 2 | 3

之后
COL1|COL2|COL3|...|REQNUM|AUTHNUM
-------- | ------ | ------ | ...|------------ | ------------|....
x |是 | z |...| 3 | 4

这是我拥有的代码,它看起来很接近但不太正确。我期待一个只有重复行的结果,所以稍后我可以通过一个 foreach 运行它,它将求和并删除额外的行。 dtrow 得到我想要的列。(感谢Linq Excluding a column)。当我尝试在查询中使用这个变量时,我没有得到任何结果,如果我删除“g.Count() > 1”,我会得到所有行,它们缺少两列。我想将所有两列保留在结果中,以后不必再添加。

        var dtRow = dtExcel.Columns.Cast<DataColumn>().Where(c => c.ColumnName != "REQNUM" && c.ColumnName != "AUTHNUM").ToList();

        var checkExcel = dtExcel.Rows.Cast<DataRow>()
            .GroupBy(x => dtRow.Select(c => x[c]))
            .Where(g => g.Count() > 1)
            .Select(gr => gr);
        //.CopyToDataTable();

感谢肯的帮助。这非常适合我需要的东西。我使用了 groupby 子句,因此我可以将重复项合并为一行并添加数字字段。还可以通过创建我在 IF 语句中使用的键进行分组。

        var dtRow = dtExcel.Columns.Cast<DataColumn>().Where(c => c.ColumnName != "REQNUM" && c.ColumnName != "AUTHNUM").ToList();

        var excelDup = dtExcel.Rows.Cast<DataRow>()
            .GroupBy(x => String.Join("", dtRow.Select(c => x[c])))
            .Select(g => 
            {
                var row = g.First();
                row.SetField("REQNUM", g.Sum(x => x.Field<double>("REQNUM")));
                row.SetField("AUTHNUM", g.Sum(x => x.Field<double>("AUTHNUM")));
                return row;
            })
            .CopyToDataTable();

我还使用 where 子句为数据行比较创建了一个变量,并且不需要键。 //使用除三之外的所有列创建变量。在下一个查询中使用 var dtExcelRow = dtExcel.Columns .Cast().Where(c => c.ColumnName != "TITLE" && c.ColumnName != "REQSTR" && c.ColumnName != "AUTHSTR").ToList(); var dtListRow = dtList.Columns .Cast().Where(c => c.ColumnName != "TITLE" && c.ColumnName != "REQSTR" && c.ColumnName != "AUTHSTR").ToList();

            // Querys create datarow list for compare
            IEnumerable<DataRow> eRow = dtExcel.AsEnumerable()
                .Where(w => dtExcelRow.Select(c => w[c]).Any())
                .Select(x => x);
            IEnumerable<DataRow> lRow = dtList.AsEnumerable()
                .Where(w => dtListRow.Select(c => w[c]).Any())
                .Select(x => x);

            // 1st compare gets list of new records that have changes or are new. 2nd is list of old records being change.
            var newRecords = eRow.AsEnumerable().Except(lRow.AsEnumerable(), DataRowComparer.Default);
            var oldRecords = lRow.AsEnumerable().Except(eRow.AsEnumerable(), DataRowComparer.Default);

【问题讨论】:

  • 感谢 Ken,这是我想出的,它非常适合我的需要。
  • var dtRow = dtExcel.Columns.Cast().Where(c => c.ColumnName != "REQNUM" && c.ColumnName != "AUTHNUM").ToList(); var excelDup = dtExcel.Rows.Cast() .GroupBy(x => String.Join("", dtRow.Select(c => x[c]))) .Select(g => { var row = g.First(); row.SetField("REQSTR", g.Sum(x => x.Field("REQSTR"))); row.SetField("AUTHNUM", g.Sum(x => x.Field("AUTHNUM"))); 返回行; }).CopyToDataTable();

标签: c# excel linq datatable duplicates


【解决方案1】:

您不能只按dtRow.Select(c =&gt; x[c]) 对数据进行分组,因为它是IEnumerable,它们可能具有相同的内容,但它们仍然不同IEnumerable

如果是string,你可以按照加入的字符串对数据进行分组:

x => String.Join("", dtRow.Select(c => x[c]))

【讨论】:

  • 谢谢肯。这让我得到了一个长字符串中的行的结果,但仍然缺少列 REQNUM 和 AUTHNUM。我想我需要这些行保持 IEnumerable,这样我就可以对重复行的列 REQNUM 和 AUTHNUM 求和。我是否错误地查看了查询? Group by 以获取与列匹配的行,然后选择组有多于一行的位置。
  • 我不确定你的意思。长字符串应该只用作分组键,这样g.Key就是一个字符串。所以 REQNUM 和 AUTHNUM 列不应该丢失,查询结果仍然是IEnumerable
  • 感谢肯回复。我按照您提到的方式保留了 groupby 并更改了我的选择并纠正了问题。我有原始问题的新代码。再次感谢您的帮助。
  • 很高兴您自己找到了答案!如果对您有帮助,请提醒我为我的回答投票。
猜你喜欢
  • 2016-02-27
  • 2017-05-17
  • 2013-11-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-21
相关资源
最近更新 更多