2

I try to group those of file revision which have the same root and make relationship between them

For example:

1.17
1.17.1.1
1.17.1.2
1.17.1.2.1.1
1.17.2.1
1.17.2.2
1.18
1.19

Now I would like to group

1.17, 1.18, 1.19 as the same group and make relationship is parent 1
1.17.1.1, 1.17.1.2 as the same group and make relationship is child 1.1
1.17.2.1, 1.17.2.2 as the same group and make relationship is child 1.2
1.17.1.2.1.1 as the same group and make relationship is grandchild 1.1.1

My idea is loop through the list and try to find number of digit by split by dot then compare it with those of list but it's seem to bad

I don't know is there any best way in VB.NET to achieve it?

The output maybe a datatable, with each data row index revision relationship 1 1.17, 1.18, 1.19 1 2 1.17.1.1, 1.17.1.2 1.1 3 1.17.2.1, 1.17.2.2 1.2 4 1.17.1.2.1.1 1.1.1

The relationship between them 1.17, 1.18, 1.19 (maybe have 1.20, 1.21...) are grouped as a root group 1.17.1.1, 1.17.1.2 (maybe have 1.17.1.3, 1.17.1.4...) are grouped as first child group of root group 1.17.2.1, 1.17.2.2 (maybe have 1.17.2.3, 1.17.2.4...) are grouped as second child group of root group 1.17.1.2.1.1 which have the same path with first child group (1.17.1.1.x.y) are grouped as a first grand child group of first child group

I really appreciate for any help and thanks so much for it.

Bruce
  • 519
  • 6
  • 23
  • Not clear enough this time. What do you mean by _relationship_? Do you mean making `1.17`, `1.18`, and `1.19` child nodes of a new node named `1`?. Maybe a tree to show the desired output and define the rule of grouping. I can understand the first group `parent 1` but not the rest. –  Apr 29 '20 at 18:11
  • @JQSOFT i have edit my question which have more detail. Please help me take a look to my question again. 1.17, 1.18, 1.19 are a root group and mark with number one. how to define output of tree – Bruce Apr 30 '20 at 04:54

1 Answers1

1

If you want to create a DataTable from the same list of revisions, then you can achieve that using the same idea with some changes for the grouping/relation issue.

Private Function ToDataTable(revs As IEnumerable(Of String)) As DataTable
    Dim dt As New DataTable

    dt.Columns.Add("Id", GetType(Integer)).AutoIncrement = True
    dt.Columns.Add("ParentId", GetType(Integer))
    dt.Columns.Add("Text", GetType(String))
    dt.Columns.Add("Path", GetType(String))
    dt.Columns.Add("ParentPath", GetType(String))
    dt.Columns.Add("Level", GetType(Integer))

    For Each rev In revs.OrderBy(Function(x) x)
        Dim arr = Regex.Matches(rev, "\d+\.\d+").
            Cast(Of Match).Select(Function(x) x.Value).ToArray()
        Dim r = dt.NewRow
        Dim parentPath = String.Join(".", arr, 0, arr.Count() - 1)

        r.SetField("ParentId", dt.Rows.Cast(Of DataRow).
            FirstOrDefault(Function(x) x.Field(Of String)("Path") = parentPath)?.
            Field(Of Integer)("Id"))
        r.SetField("Text", rev)
        r.SetField("Path", rev)
        r.SetField("ParentPath", parentPath)
        r.SetField("Level", arr.Count)

        dt.Rows.Add(r)
    Next

    Return dt
End Function

Also you can create a DataTable from the populated TreeView in the last answer:

Private Iterator Function GetAllNodes(nodes As TreeNodeCollection) _
    As IEnumerable(Of TreeNode)
    For Each tn In nodes.Cast(Of TreeNode)
        Yield tn
        For Each cn In GetAllNodes(tn.Nodes)
            Yield cn
        Next
    Next
End Function

Private Function ToDataTable(tv As TreeView) As DataTable
    Dim dt As New DataTable

    dt.Columns.Add("Id", GetType(Integer)).AutoIncrement = True
    dt.Columns.Add("ParentId", GetType(Integer))
    dt.Columns.Add("Text", GetType(String))
    dt.Columns.Add("Path", GetType(String))
    dt.Columns.Add("ParentPath", GetType(String))
    dt.Columns.Add("Level", GetType(Integer))

    For Each node In GetAllNodes(tv.Nodes)
        Dim r = dt.NewRow
        Dim parentPath = node.Parent?.Text

        r.SetField("ParentId", dt.Rows.Cast(Of DataRow).
                    FirstOrDefault(Function(x) x.Field(Of String)("Path") = parentPath)?.
                    Field(Of Integer)("Id"))
        r.SetField("Text", node.Text)
        r.SetField("Path", node.Text)
        r.SetField("ParentPath", parentPath)
        r.SetField("Level", node.Level + 1)

        dt.Rows.Add(r)
    Next

    Return dt
End Function

Note here, the node's Level property returns the branch level/group/relation of each node.

  • Thanks so much for you answer but it's not at all my purpose. The "Relation" field in your code just only a level, not relation. For example, with a group "first child node" (1.17.1.1, 1.17.1.2) and group "second child node" (1.17.2.1, 1.17.2.2), follow your code we just only know level of grand child node (1.17.1.2.1.1) is level 3, we don't know whether is it belong to "first child node" or "second child node". Do you have any idea to achieve it? – Bruce Apr 30 '20 at 15:54
  • @Bruce The **Path** field of each row tells you the hierarchy of the node. This is why that field exists. So the path `1.17.1.2.1.2.1.5.1.2.1.1` for example, tells you exactly and precisely which child of which parent. You need to find out the relation in your code. In a single DataTable you just can do something like my post. –  Apr 30 '20 at 17:11
  • Thanks so much JQSOFT I am finnally find the solution for myself. It's need to build a algrorism for itself. However thanks so much for your idea and help – Bruce May 02 '20 at 15:00