【问题标题】:DataTable Combine Values and Remove Source RowsDataTable 合并值并删除源行
【发布时间】:2016-08-05 14:38:01
【问题描述】:

我创建了一个数据表,我正在尝试减少行数。我能够找到一种方法来检查表中是否存在 testID 并合并主机名,但我不确定如何删除源行。

例如dtOrginal:

testID passFail description hostname
1ab    pass     ....        alpha
1ab    pass     ....        bravo
1ab    fail     ....        charlie
1ac    pass     ....        alpha

当前结果示例:

testID passFail description hostname
1ab    pass     ....        alpha, bravo
1ab    pass     ....        bravo
1ab    fail     ....        charlie
1ac    pass     ....        alpha

我想要得到什么

testID passFail description hostname
1ab    pass     ....        alpha, bravo
1ab    fail     ....        charlie
1ac    pass     ....        alpha

这是我当前在必要时合并主机名和 testID 的函数

DataTable dtReducedColumns = CombineHostnames(dtOrinal).Copy();

private static DataTable CombineHostnames(DataTable dt)
    {
        for (int i = 0; i < dtOrginal.Rows.Count; i++)
        {
            bool isDupe = false;
            string a, b, c, d, e, f, g, h, k, l;

            for (int j = 0; j < dt.Rows.Count; j++)
            {
                a = dtOrginal.Rows[i][0].ToString(); //testID
                b = dt.Rows[j][0].ToString();
                c = dtOrginal.Rows[i][1].ToString(); //passFail
                d = dt.Rows[j][1].ToString();
                g = dtOrginal.Rows[i][2].ToString(); //description
                h = dt.Rows[j][2].ToString();
                if (a == b && c == d && g == h)
                {
                    e = dt.Rows[j][10].ToString();
                    f = dtOrginal.Rows[i][10].ToString(); //hostname
                    k = dtOrginalRows[i][8].ToString(); //source
                    l = dt.Rows[j][8].ToString();
                    if (!e.Contains(f))
                        dt.Rows[j][10] = e + ", " + f; //combine hostnames
                    if (!k.Contains(l))
                        dt.Rows[j][8] = k + ", " + l; //combine sources
                    isDupe = true;
                    //tried adding dt.Rows[j].Delete() here
                    //tried adding dt.Rows[j-1].Delete() here get -1 error
                    break;
                } 
               //tried adding dt.Rows[j].Delete() here
               //tried adding dt.Rows[j-1].Delete() here get -1 error
            }
            //tried adding dt.Rows[j].Delete() here
            //tried adding dt.Rows[j-1].Delete() here get -1 error

            if (!isDupe)
            {
                dt.ImportRow(dtOrginal.Rows[i]);
            }
        }
        return dt;
    }

我尝试删除行的地方要么引发IndexOutOfBounds 异常,要么返回类似于dtOrginal 的表。

作为参考,这是我正在使用的整个 DataTable:

dtChecklistFindingsTable = new DataTable();                                  //Column Number
dtChecklistFindingsTable.Columns.Add("testID", typeof(string));              // 0
dtChecklistFindingsTable.Columns.Add("passFail", typeof(string));            // 1
dtChecklistFindingsTable.Columns.Add("description", typeof(string));         // 2
dtChecklistFindingsTable.Columns.Add("vulLevel", typeof(string));            // 3
dtChecklistFindingsTable.Columns.Add("recommendation", typeof(string));      // 4
dtChecklistFindingsTable.Columns.Add("comments", typeof(string));            // 5
dtChecklistFindingsTable.Columns.Add("title", typeof(string));               // 6
dtChecklistFindingsTable.Columns.Add("testCheck", typeof(string));           // 7
dtChecklistFindingsTable.Columns.Add("source", typeof(string));              // 8
dtChecklistFindingsTable.Columns.Add("date", typeof(string));                // 9
dtChecklistFindingsTable.Columns.Add("hostName", typeof(string));            // 10
dtChecklistFindingsTable.Columns.Add("os", typeof(string));                  // 11
dtChecklistFindingsTable.Columns.Add("ipAddr", typeof(string));              // 12
dtChecklistFindingsTable.Columns.Add("stigLevel", typeof(string));           // 13
dtChecklistFindingsTable.Columns.Add("stigSeverity", typeof(string));        // 14
dtChecklistFindingsTable.Columns.Add("sarStatus", typeof(string));           // 15
dtChecklistFindingsTable.Columns.Add("iaControl", typeof(string));           // 16

【问题讨论】:

    标签: c# datatable


    【解决方案1】:

    这是Linq-To-DataTable 的一个很好的用例,尤其是Enumerable.GroupBy + String.Join

    private static DataTable CombineHostnames(DataTable dtOrginal)
    {
        DataTable tblresult = dtOrginal.Clone(); // empty table, same columns
        var rowGroups = dtOrginal.AsEnumerable()
            .GroupBy(row => new
            {
                Id = row.Field<string>("testId"),
                passFail = row.Field<string>("passFail")
            });
    
        foreach (var group in rowGroups)
        {
            DataRow row = tblresult.Rows.Add(); // already added now
            row.SetField("testId", group.Key.Id);
            row.SetField("passFail", group.Key.passFail);
            row.SetField("description", group.First()["description"]);  // the first?
            string hostNames = String.Join(", ", group.Select(r => r.Field<string>("hostname")));
            row.SetField("hostname", hostNames);
        }
        return tblresult;
    }
    

    您可以使用与我已经添加 description 相同的方式添加其他列,只需使用每个组中的第一个或其他逻辑即可。

    【讨论】:

    • 太完美了,非常感谢!由于 testID 是字母数字,因此做了一些小修改,我将其更改为字符串,SetField("description"...) 中有一个多余的空格被我删除了。
    • 有没有办法在加入字符串之前进行检查?换句话说,我希望某些字段具有相同的 ID 但来自不同的来源,我想合并这些来源,但只有唯一的来源?
    • 我尝试使用 .Distinct() 但它给了我几次 System.Linq.Enumerable+&lt;DistinctIterator&gt;d__631[System.Char]`
    • 也许您可以为此提出另一个问题,其他人可以提供帮助。我现在在放假:)
    • 呃,我刚刚创建了一个单独的辅助方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-19
    • 1970-01-01
    相关资源
    最近更新 更多