【问题标题】:How to count and rename duplicate rows in a DataTable如何计算和重命名 DataTable 中的重复行
【发布时间】:2013-05-28 13:47:51
【问题描述】:

我发现了很多关于删除重复项的内容,但我在任何地方都找不到针对以下问题的任何指导...

我正在寻找一种方法来重命名从 CSV 导入的 C# DataTable 中的任何重复行。我的数据看起来像:

**Name**       **Item**                 **Quantity**
ABC            Item_Name                     6
ABC            Item_Name_2                   1
DEF            Item_Name                     3
GHI            Item_Name_2                   7
ABC            Item_Name                     6
ABC            Item_Name                     1
JKL            Item_Name_3                   4
ABC            Item_Name                     6
ABC            Item_Name                     1
JKL            Item_Name_3                   4

如果一整行(包括数量)多次出现,我希望数据是什么样子,是这样的:

**Name**          **Item**                 **Quantity**
ABC            Item_Name                        6
ABC            Item_Name_2                      1
DEF            Item_Name                        3
GHI            Item_Name_2                      7
ABC (2)        Item_Name                        6
ABC (2)        Item_Name_2                      1
JKL            Item_Name_3                      4
ABC (3)        Item_Name                        6
ABC (3)        Item_Name_2                      1
JKL (2)        Item_Name_3                      4

目前,我正在使用双“for 循环”来确定表下方的哪些行与当前行具有相同的数据并相应地重命名它们。显然,这有两个问题:

  1. 很明显,对于具有大量行的表,它确实很慢

  2. 所有名称列为“ABC”的未来行现在都有一个名称列“ABC (2)”,无论这是它们的第 2 次还是第 98 次出现(因为,坦率地说,我的代码很烂) .

任何人都可以提供任何帮助非常感谢:)

【问题讨论】:

    标签: c# datatable duplicates datarow


    【解决方案1】:
        foreach(DataRow row in thisTable.Rows)
        {
            string name = row.Item[0].ToString();
    
            if(name[name.Length - 3] == '(' && name[name.Length - 1] == ')')
                continue;
    
            string item = row.Item[1].ToString();
            int quantity = Convert.ToInt32(row.Item[2]);
            string expression = "Name = " + name + " and Item = " + item + " and Quantity = " + quantity;
    
            DataRow[] matchingRows = table.Select(expression);
            for(int i = 1; i < matchingRows.Length; i++)
                matchingRows[i]["Name"] += " (" + i + ")";  
        }
    

    基本上,我只是遍历每一行。然后,我查询相同的每一行。然后,我遍历这些相同的行,并用附加的字符串 (1)、(2)、(3) 等重命名它们(按照查询找到它们的顺序)。我还跳过了我已经使用该“if”语句重命名的任何行(我假设重命名的行在第 3 个到最后一个字符处以“(”结尾,在最后一个字符处以“)”结尾)。抱歉,如果我在代码中犯了与 C# 语法相关的错误。不过,这个想法非常简单。

    【讨论】:

    • 除了将更改提交到 DataTable 之外,它所做的一切都是正确的。我无法将行导入或加载到表中,因为它与“foreach”中的“in”枚举冲突。有什么建议吗?
    • 嗯。尝试matchingRows[i]["Name"] += " (" + i + ")" OR matchingRows[i].SetField("Name", matchingRows[i]["Name"] + " (" + i + " )”)。如果这不起作用,请尝试设置 thisTable.Columns.readOnly = false。
    • 是的...使用 matchingRows[i]["Name"] 将其整理出来。是否有一个合乎逻辑的解释为什么对命名列进行更改而对 ItemArray 进行更改不起作用?这是我在这里提出的第一个问题,我应该编辑您的答案以包含该更改,然后将其标记为解决方案吗?这通常是这样工作的吗?
    • item 数组只是该行内容的副本,而不是实际引用。所以你实际上并没有修改真正的行。生病编辑答案,然后您可以将其标记为解决方案。
    【解决方案2】:

    这是一个不同的解决方案。在我看来,更优雅!

            DataTable table = new DataTable();
            table.Columns.Add("Name", typeof(string));
            table.Columns.Add("Title", typeof(string));
            table.Columns.Add("Quantity", typeof(int));
    
            // Data for test
            table.Rows.Add("ABC", "Item_name", 6);
            table.Rows.Add("ABC", "Item_name", 6);
            table.Rows.Add("ABC2", "Item_name", 6);
            table.Rows.Add("ABC2", "Item_name", 6);
            table.Rows.Add("ABC2", "Item_name", 6);
            table.Rows.Add("ABC2", "Item_name", 6);
    
            // Query with Linq
            var query = from row in table.AsEnumerable()
                        group row by new {
                            name  = row.Field<String>("Name"),
                            title = row.Field<String>("Title")
                        } into GrpNameTitle
                        select new {
                            Name  = GrpNameTitle.Key.name + " (" + GrpNameTitle.Count() + ")", 
                            Title = GrpNameTitle.Key.title,
                            Quantity = GrpNameTitle.First().Field<int>("Quantity")
                        };
    
    
            foreach (var itm in query)
            {
                Console.WriteLine("{0}\t{1}", itm.Name, itm.Title);
            }
    

    我有一个问题,当您在两列(名称和标题)上过滤行“分组依据”时,添加/计算第三列包含数量是否没有意义?例如:

    abc item_name 2
    abc item_name 2
    

    给出这个结果:

    abc(2) item_name 4
    

    最好的问候,

    导师雷卡。

    【讨论】:

    • 好主意,但不,这不是我想要实现的目标。我可能应该更清楚我的最终目标。我只想将这些数据行标记为合法重复,因为源 CSV 构成最终用户可以从中下订单的东西的一部分,所以我只想将这些行标记为相同类型订单的单独实例以显示它们没有输入错误。
    • 感谢您的回答 :-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-10
    • 2011-12-29
    • 2021-01-17
    • 1970-01-01
    • 2017-06-12
    • 2020-12-31
    • 2021-03-08
    相关资源
    最近更新 更多