C# - 创建平面列表的树结构(按日期)

Posted

技术标签:

【中文标题】C# - 创建平面列表的树结构(按日期)【英文标题】:C# - Create a tree structure of a flat list (by dates) 【发布时间】:2015-01-12 14:30:50 【问题描述】:

我有一个包含许多文件的列表。我想以树结构而不是平面列表显示此列表。 像这样的:

2001
- 2001-01
    -2001-01-01
        -File 1
        -File 2
        -File 3
        -File 4
    -2001-01-02
        -File 5
        -File 6
        -File 7
        -File 8
    -2001-01-03
        - etc
    -2001-01-03
etc...

我发现了类似的东西,但不知道如何在我的设置中应用它。 How to efficiently build a tree from a flat structure?

这些文件有一个 DateTime 字段,我可以在其中获取日期。

我可以将我所有的文件都归为同一日期吗?

编辑: 现在列表是这样显示的

2001-01-01 - File 1
2001-01-01 - File 2
2001-01-01 - File 3
2001-01-01 - File 4
2001-01-02 - File 5
2001-01-02 - File 6
2001-01-02 - File 7
etc

【问题讨论】:

我不太确定你的问题到底出在哪里。也许您正在寻找TreeView class 我的问题是我得到了一个平面列表。如果我循环通过它,我会得到: 2001-01-01 - 文件 1 2001-01-01 - 文件 2 2001-01-01 - 文件 3 2001-01-01 - 文件 4 2001-01-02 - 文件 5 等我想在我的问题中有结构。 对。您需要将它们分类为列表和嵌套列表.. 甚至可能是三层深度。你的第一个级别是按年份。在该列表中,维护年+月的列表。在该列表中,维护年+月+日的列表。完成将文件列表扩展到此层次结构后,递归遍历每个列表,并构建带有节点的树。 您是希望它创建某种树视图对象,还是只想输出文本或 html 【参考方案1】:

我假设您有一个名为 FileInfo 对象文件的排序数组。然后你可以像这样遍历它:

foreach (FileInfo fi in Files)

    AddNode(fi);

AddNode 成员将节点添加到树中:

private void AddNode(FileInfo F)

    // Create the node labels.
    string y = String.Format("0:yyyy", F.LastWriteTime);
    string ym = String.Format("0:yyyy-MM", F.LastWriteTime);
    string ymd = String.Format("0:yyyy-MM-dd", F.LastWriteTime);

    TreeNode[] tnY = null;
    TreeNode[] tnYM = null;
    TreeNode[] tnYMD = null;

    // Find existing tree nodes for the file we are working on.
    tnY = treeView1.Nodes.Find(y, false);
    if (tnY.Length == 1)
    
        tnYM = tnY[0].Nodes.Find(ym, false);
        if (tnYM.Length == 1)
        
            tnYMD = tnYM[0].Nodes.Find(ymd, false);
        
    

    // Create the missing nodes.
    if (tnY.Length == 0)
    
        tnY = new TreeNode[1];
        tnY[0] = treeView1.Nodes.Add(y, y);
    
    if (tnYM == null || tnYM.Length == 0)
    
        tnYM = new TreeNode[1];
        tnYM[0] = tnY[0].Nodes.Add(ym, ym);
    
    if (tnYMD == null || tnYMD.Length == 0)
    
        tnYMD = new TreeNode[1];
        tnYMD[0] = tnYM[0].Nodes.Add(ymd, ymd);
    

    // And finally, add the node with the file name.
    tnYMD[0].Nodes.Add(F.Name);

【讨论】:

【参考方案2】:

基本思想是跟踪前一年、一个月和一天,以便您知道是否应该创建新的父节点。你没有说你希望它显示在树视图中,所以我假设你希望它在标准文本或 HTML 中。使其成为树视图控件在实现上稍微复杂一些,但基本思想没有什么不同。

我将介绍伪代码,而不是陷入 C# 实现的细节。这将使我更容易理解这些想法,并且更容易让您移植到适合您的数据和输出方法所需的任何形式。

这假定文件按日期排序,最早的日期(即最早的文件)在前。

首先将前一天、一个月和一年设置为 -1:

previousYear = -1
previousMonth = -1
previousDay = -1
for each file in list

    if (file.date.year != previousYear)
    
        output file.date.year
        previousYear = file.date.year
        // set previousMonth to default to force a new month folder
        previousMonth = -1
    
    if (file.date.Month != previousMonth)
    
        output file.date.month
        previousMonth = file.date.month
        // set previousDay to default to force a new day folder
        previousDay = -1
    
    if (file.date.day != previousDay)
    
        output file.date.day
        previousDay = file.date.day
    
    // and then output the file name
    output file.name

【讨论】:

谢谢先生!这个做到了。我做了一些更改以正确显示它。 pastebin.com/gTGdkdNB【参考方案3】:

好的,这只是一个非常简单的实现,但它可以解决问题:)

List<string> files = new List<string>()

    "2001-01-01 - File 1",
    "2001-01-01 - File 2",
    "2001-01-02 - File 1",
    "2001-01-03 - File 1"
;

TreeView tv = new TreeView();

foreach(string file in files)

    string y = file.Substring(0, 4);
    string ym = file.Substring(0, 7);
    string ymd = file.Substring(0, 10);
    string fn = file.Substring(13);

    TreeNode Node = tv.Nodes[y] ?? tv.Nodes.Add(y,y);
    Node = Node.Nodes[ym] ?? Node.Nodes.Add(ym,ym);
    Node = Node.Nodes[ymd] ?? Node.Nodes.Add(ymd,ymd);
    Node.Nodes.Add(fn);

编辑:所以,我并没有真正注意到使用日期时间的信息。为此,我现在使用一个列表,其中包含具有 DateTime 和字符串文件名的类:

List<fi> files = new List<fi>()

    new fi(new DateTime(2001, 1, 1), "File 1"),
    new fi(new DateTime(2001, 1, 1), "File 2"),
    new fi(new DateTime(2001, 1, 3), "File 3"),
    new fi(new DateTime(2001, 1, 1), "File 4"),
    new fi(new DateTime(2001, 1, 2), "File 5"),
    new fi(new DateTime(2001, 1, 2), "File 6"),
    new fi(new DateTime(2001, 1, 2), "File 7")
;

TreeView tv = new TreeView();

var orderedfiles = from file in files orderby file.date ascending select file;
foreach(fi file in orderedfiles)

    TreeNode Node = tv.Nodes[file.date.Year.ToString()] ?? tv.Nodes.Add(file.date.Year.ToString(), file.date.Year.ToString());
    Node = Node.Nodes[file.date.ToString("yyyy-mm")] ?? Node.Nodes.Add(file.date.ToString("yyyy-mm"), file.date.ToString("yyyy-mm"));
    Node = Node.Nodes[file.date.ToString("yyyy-mm-dd")] ?? Node.Nodes.Add(file.date.ToString("yyyy-mm-dd"), file.date.ToString("yyyy-mm-dd"));
    Node.Nodes.Add(file.fn);

【讨论】:

以上是关于C# - 创建平面列表的树结构(按日期)的主要内容,如果未能解决你的问题,请参考以下文章

C#中的树数据结构

平面数组重组为树数组

邻接表的树结构

将数据框转换为列表的树结构列表

如何从 VB.NET 中的 XML 文件构建唯一的树结构

Qt 模型的树视图和表视图