从列表中递归地删除子父关系

Remove child parent relationship recursively from a list

我有一个包含数据行对象的列表,这些对象具有两个属性,一个 Id 和一个 prentId。一个例子是这样的:

id    ParentId
130   -1
131   130
132   131
133   131
134   132
135   131
136   132
137   136
138   136
139   136
143   136

如果从层次结构的角度来看列表,它将如下所示:

130
    131
        132
            134
            136
                137
                138
                139
                143
        133
        135

我想做的是创建一个算法,删除父元素与特定 ID 匹配的所有元素和子元素。

例如,如果选择的 ID 为 132,则应删除 ID 为 132、134、136、137、138、139、143 的元素。

到目前为止我尝试的是这样的

    Private Function RemoveRecursive(ByRef values As List(Of DataRow), value As String) As List(Of DataRow)
        For index As Integer = values.Count - 1 To 0 Step -1
            If Not IsDBNull(values(index)("parent")) AndAlso values(index)("parent") = value Then
                values.RemoveAt(index)
                Return RemoveRecursive(values, value)
                value = values(index)("id")
            End If
        Next
        Return values
    End Function

根据提供的数据,我假设 133 和 135 也想删除,因为它们是 children 的 131?

实现您想要的目标的一种方法可能是;

  • 创建 'tagged' 个条目的空列表
  • 遍历列表,如果 ParentID == 131 或 ParentID 在标记条目列表中,则将此节点添加到标记条目
  • 从您的原始数据集中删除所有标记的 objects

我试图解决你的问题 (c#):

private static void RemoveRecursive(List<DataRow> values, string valueToRemove) {
    DataRow itemToRemove = values.Find(dr => (string)dr["id"] == valueToRemove);
    values.Remove(itemToRemove);
    IEnumerable<string> children = values.Where(dr => (string)dr["ParentId"] == valueToRemove).Select(dr => (string)dr["id"]);
    foreach (string child in children)
        RemoveRecursive(values, child);
}

您可以通过以下方式调用此方法:

RemoveRecursive(values, "131");

您还可以添加一些空检查。

离你不远了。您错过了两件事:

  1. 如果当前行 id 等于搜索值,而不仅仅是 parent
  2. 您在对 RemoveRecursive 的内部调用之后设置重估,因此它使用与初始值相同的值,即它每次只会检查 132

1 号只需要扩展您的 if 语句。对于数字 2,我只是将当前 id 值存储在一个新变量中,然后再删除该行并将其传递给递归调用:

Private Function RemoveRecursive(ByRef values As List(Of DataRow), value As String) As List(Of DataRow)
    For index As Integer = values.Count - 1 To 0 Step -1
        If Not IsDBNull(values(index)("parent")) AndAlso (values(index)("parent") = value OrElse values(index)("id") = value) Then
            Dim newValue as integer = values(index)("id").ToString()
            values.RemoveAt(index)
            RemoveRecursive(values, newValue)
        End If
    Next
    Return values
End Function

Working .NETFiddle

parent / child 的一般示例可能会有所帮助。这是乐观的,因为没有错误检查。请注意,Add 和 Remove 方法都被重载了。

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim root As New PC(1)
    root.AddChild(1, 10)
    root.AddChild(1, 11)
    root.AddChild(1, 12)
    root.AddChild(11, 110)
    root.AddChild(11, 111)
    root.AddChild(110, 1100)
    root.AddChild(110, 1101)
    root.AddChild(1100, 11000)
    root.AddChild(1100, 11001)
    root.AddChild(1101, 11010)
    root.RemoveChild(1100)
End Sub

Class PC 'parent child
    Dim myID As Integer
    Dim parentPC As PC = Nothing
    Dim children As New List(Of PC)

    Public Sub New(ID As Integer)
        Me.myID = ID
    End Sub

    Public Function AddChild(parent As Integer, child As Integer) As PC
        Dim rv As PC
        rv = Me.AddChild(Me, parent, child)
        Return rv
    End Function

    Private Function AddChild(aPC As PC, parent As Integer, child As Integer) As PC
        Dim rv As PC
        Dim addPC As PC
        If aPC.myID = parent Then
            addPC = New PC(child)
            addPC.children = New List(Of PC)
            addPC.parentPC = aPC
            aPC.children.Add(addPC)
            Return addPC
        Else
            For Each chld As PC In aPC.children
                rv = chld.AddChild(chld, parent, child)
                If rv IsNot Nothing Then
                    Exit For
                End If
            Next
        End If
        Return rv
    End Function

    Public Function RemoveChild(child As Integer) As Boolean
        Dim rv As Boolean = False
        rv = Me.RemoveChild(child, Me)
        Return rv
    End Function

    Private Function RemoveChild(child As Integer, aPC As PC) As Boolean
        Dim rv As Boolean = False
        If aPC.myID = child Then
            For x As Integer = aPC.children.Count - 1 To 0 Step -1
                Dim chld As PC = aPC.children(x)
                Me.RemoveChild(chld.myID, chld)
            Next
            aPC.parentPC.children.Remove(aPC)
            aPC.children = Nothing
            aPC = Nothing
            rv = True
        Else
            For Each chld As PC In aPC.children
                rv = Me.RemoveChild(child, chld)
                If rv Then
                    Exit For
                End If
            Next
        End If
        Return rv
    End Function
End Class