VB.NET - 根据共享值合并 DataTable 中的行

VB.NET - Combine rows in DataTable based on shared value

我正在尝试根据行的共享 ID 将行合并到 DataTable 中。 table 数据看起来像这样:

Member | ID   | Assistant | Content
---------------------------------------------
16     | 1234 | jkaufman  | 1/1/2015 - stuff1
16     | 1234 | jkaufman  | 1/2/2015 - stuff2
16     | 4321 | mhatfield | 1/3/2015 - stuff3
16     | 4321 | mhatfield | 1/4/2015 - stuff4
16     | 4321 | mhatfield | 1/5/2015 - stuff5
16     | 5678 | psmith    | 1/6/2015 - stuff6

我想根据匹配的 ID 合并行。有两个步骤我可以使用一些澄清。首先是合并行。第二个是组合内容列,这样内容就不会丢失。对于上面的例子,这是我想要的:

Member | ID   | Assistant | Content
-------------------------------------------------------------------------------------------
16     | 1234 | jkaufman  | 1/1/2015 - stuff1 \r\n 1/2/2015 - stuff2
16     | 4321 | mhatfield | 1/3/2015 - stuff3 \r\n 1/4/2015 - stuff4 \r\n 1/5/2015 - stuff5
16     | 5678 | psmith    | 1/6/2015 - stuff6

我的最终目标是将 DataTable 复制到 Excel 电子表格,因此我不确定 \r\n 是否是正确的换行符,但这是我最不关心的此时。

现在这是我的代码(编辑:更新为当前代码):

Dim tmpRow As DataRow
dtFinal = dt.Clone()

Dim i As Integer = 0
While i < dt.Rows.Count
    tmpRow = dtFinal.NewRow()
    tmpRow.ItemArray = dt.Rows(i).ItemArray.Clone()
    Dim j As Integer = i + 1
    While j <= dt.Rows.Count
        If j = dt.Rows.Count Then 'if we've iterated off the end of the datset
            i = j
            Exit While
        End If
        If dt.Rows(i).Item("ID") = dt.Rows(j).Item("ID") Then 'if we've found another entry for this id
            'append change to tmpRow
            tmpRow.Item("Content") = tmpRow.Item("Content").ToString & Environment.NewLine & dt.Rows(j).Item("Content").ToString
        Else 'if we've run out of entries to combine
            i = j
            Exit While
        End If

        j += 1
    End While
    'add our combined row to the final result
    dtFinal.ImportRow(tmpRow)
End While

当我将最终的 table 导出到 Excel 时,电子表格是空白的,所以我肯定做错了什么。

任何帮助都会很棒。谢谢!

我发现您的方法存在各种问题(对于两个版本;但第二个似乎更好)。这就是为什么我更愿意编写完整的工作代码来帮助清楚地传达我的想法。

    Dim dtFinal As DataTable = New DataTable
    For Each col As DataColumn In dt.Columns
        dtFinal.Columns.Add(col.ColumnName, col.DataType)
    Next

    Dim oldRow As Integer = -1
    Dim row As Integer = -1
    While oldRow < dt.Rows.Count - 1

        dtFinal.Rows.Add()
        row = row + 1

        oldRow = oldRow + 1
        Dim curID As String = dt.Rows(oldRow)(1).ToString()
        Dim lastCol As String = ""
        While (oldRow < dt.Rows.Count AndAlso dt.Rows(oldRow)(1).ToString() = curID)
            lastCol = lastCol & dt.Rows(oldRow)(3).ToString() & Environment.NewLine
            oldRow = oldRow + 1
        End While

        oldRow = oldRow - 1

        For i As Integer = 0 To 2
            dtFinal.Rows(row)(i) = dt.Rows(oldRow)(i)
        Next
        dtFinal.Rows(row)(3) = lastCol

    End While

请注意,尝试提出最多 "elegant" 的解决方案或最大化给定的内置功能可能不是应对某些情况的最佳方式。例如,在您提出的问题中,我认为最好是逐步进行(并且只有在正确工作的版本到位后才能减少代码 size/improving 优雅)。这是我在这里尝试创建的一种代码:一种提供预期功能的简单代码(我认为这正是您想要的功能;无论如何,请记住,我包含了您所期望的简单代码仅作为理解这一点的帮助)。

我发现 VB 语法与 C# 中的语法相比显得笨拙,但您可能更喜欢这个带分组解决方案的 Linq:

Dim merge = (From rw In dt.Rows.OfType(Of DataRow)()
            Group rw By
                New With {.fld1 = rw(0)}.fld1,
                New With {.fld2 = rw(1)}.fld2,
                New With {.fld3 = rw(2)}.fld3 Into Group).
                    Select(Function(x)
                               Return New With {.Member = x.fld1,
                                                .ID = x.fld2,
                                                .Assistant = x.fld3,
                                                .Content = String.Join("", x.Group.Select(Function(y)
                                                                                              Return String.Join("", y.ItemArray)
                                                                                          End Function))}
                           End Function)