从数据表中删除重复项

时间:2014-04-23 17:42:48

标签: c# linq datatable

我试图删除与this question类似的数据表中的重复项。但是,当我这样做时,我需要在有序数据集上执行此操作,因为其中一个标准是时间是我的列之一,而且我只需要保留最早的时间实例。

我也在ordered lists from a datatable上遇到了这个问题,但我不确定如何将两者结合起来。

基本上,我正在将文件读入数据集,然后我想按时间排序和其他三列,并删除所有重复项,留下最早的时间实例。有问题的列是Name(int),电话号码(长),时间(int)和位置(字符串)。如果姓名,电话和位置重复,请在第一个(最早)时间之后删除所有内容。

dsHoldingSet.Tables["FileData"].Columns.Add("location", typeof(string));
dsHoldingSet.Tables["FileData"].Columns.Add("name", typeof(int));
dsHoldingSet.Tables["FileData"].Columns.Add("field", typeof(string));
dsHoldingSet.Tables["FileData"].Columns.Add("time", typeof(int));
dsHoldingSet.Tables["FileData"].Columns.Add("phone", typeof(long));
dsHoldingSet.Tables["FileData"].Columns.Add("field", typeof(int));
dsHoldingSet.Tables["FileData"].Columns.Add("field", typeof(string));
dsHoldingSet.Tables["FileData"].Columns.Add("field", typeof(Boolean));
dsHoldingSet.Tables["FileData"].Columns.Add("field", typeof(string));
dsHoldingSet.Tables["FileData"].Columns.Add("field", typeof(Boolean));
dsHoldingSet.Tables["FileData"].Columns.Add("field", typeof(Boolean));
dsHoldingSet.Tables["FileData"].Columns.Add("field", typeof(string));
dsHoldingSet.Tables["FileData"].Columns.Add("field", typeof(int));
dsHoldingSet.Tables["FileData"].Columns.Add("field", typeof(int));
dsHoldingSet.Tables["FileData"].Columns.Add("field", typeof(Boolean));
dsHoldingSet.Tables["FileData"].Columns.Add("field", typeof(Boolean));
dsHoldingSet.Tables["FileData"].Columns.Add("field", typeof(Boolean));
dsHoldingSet.Tables["FileData"].Columns.Add("field", typeof(string));
dsHoldingSet.Tables["FileData"].Columns.Add("field", typeof(int));
dsHoldingSet.Tables["FileData"].Columns.Add("field", typeof(int));
dsHoldingSet.Tables["FileData"].Columns.Add("field", typeof(long));
dsHoldingSet.Tables["FileData"].Columns.Add("field", typeof(string));
dsHoldingSet.Tables["FileData"].Columns.Add("field", typeof(string));
dsHoldingSet.Tables["FileData"].Columns.Add("field", typeof(Boolean));
dsHoldingSet.Tables["FileData"].Columns.Add("field", typeof(Boolean));
dsHoldingSet.Tables["FileData"].Columns.Add("field", typeof(Boolean));
dsHoldingSet.Tables["FileData"].Columns.Add("field", typeof(Boolean));
dsHoldingSet.Tables["FileData"].Columns.Add("field", typeof(string));
dsHoldingSet.Tables["FileData"].Columns.Add("field", typeof(string));

这是表定义,然后我们在文件中验证行时添加行。

1 个答案:

答案 0 :(得分:2)

我们想要做的是按不同的值对行进行分组。如果我们想对数据表使用LINQ,最简单的方法是使用内置的DataTable.AsEnumerable() extension method。这会为您返回IEnumerable<DataRow>

一旦我们得到了这个,我们需要从三个值的复合中构造一个可比较的对象。这里我使用了字符串连接的方法,因为字符串很容易比较。还有其他方法可以做到这一点,但这个很简单:

  

名称|电话|位置

这会产生一系列IGrouping<string, DataRow>。每个分组也是IEnumerable<DataRow>,表示该组的子集。因此,如果我们按时间对每个分组对象进行排序,并将第一个对象拉出来,那就是第一行。

这是完整的代码。

var rows = dsHoldingSet.Tables["FileData"].AsEnumerable()
    .GroupBy(row => string.Format("{0}|{1}|{2}",
        row.Field<string>("name"),
        row.Field<string>("phone"),
        row.Field<string>("location"))
    .Select(group => 
        group.OrderBy(row => row.Field<TimeSpan>("time")).First());

其他一些注意事项 - phone应该是一个字符串,而不是一个字符串;除非time表示您尚未进入的其他类型的衡量标准,否则它应该是TimeSpan或DateTime。加载数据集进行操作时,您要做的第一件事就是将数据强制转换为最强大和最正确的数据类型 - 这使得实际操作变得更容易。如果你需要完成它,你可以撤回。