Как создать коллекцию из списка строк, который представляет структуру каталогов в C # или VB - PullRequest
1 голос
/ 21 февраля 2012

Во-первых, я проверил этот пост , но, во-первых, он находится в Python, а во-вторых, создается впечатление, что он фактически создает каталоги, что я не могу сделать в этом сценарии.

Второйэто не каталоги, которые существуют, и я не могу их создать.

У меня есть вход в C #, например:

        List<string> filePaths = new List<string>();
        filePaths.Add(@"ProgramDir\InstallDir\Module1\mod1pack1.exe");
        filePaths.Add(@"ProgramDir\InstallDir\Module1\mod1pack2.exe");
        filePaths.Add(@"ProgramDir\InstallDir\Module2\mod2pack1.exe");
        filePaths.Add(@"ProgramDir\InstallDir\Module1\SubModule1\report1.rpt");
        filePaths.Add(@"SystemDir\DependencyDir\dependency1.dll");
        filePaths.Add(@"SystemDir\DependencyDir\dependency2.dll");

Я пытался создать объект, которыйпредставляет эту структуру, такую, что ее можно визуализировать следующим образом:

-ProgramDir
    Installdir
        Module1
            mod1pack1.exe
            mod1pack2.exe
            -SubModule1
                 report1.rpt
        Module2
            mod2pack1.exe
-SystemDir
    -DependencyDir
         dependency1.dll
     dependency2.dll

Я пробовал разные версии следующего, и я мог бы действительно использовать некоторую помощь, чтобы выяснить, где я ошибся.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            SetFilePathList();
            DTree forest = new DTree();
            List<DTreeBranch> branches = new List<DTreeBranch>();
            foreach (string path in filePaths)
            {
                forest.GrowTree(path.Split('\\'), branches);
            }
            forest.SubBranches.AddRange(branches);
        }
        private static List<string> filePaths { get; set; }
        private static void SetFilePathList()
        {
            filePaths = new List<string>();
            filePaths.Add(@"ProgramDir\InstallDir\Module1\mod1pack1.exe");
            filePaths.Add(@"ProgramDir\InstallDir\Module1\mod1pack2.exe");
            filePaths.Add(@"ProgramDir\InstallDir\Module2\mod2pack1.exe");
            filePaths.Add(@"ProgramDir\InstallDir\Module1\SubModule1\report1.rpt");
            filePaths.Add(@"SystemDir\DependencyDir\dependency1.dll");
            filePaths.Add(@"SystemDir\DependencyDir\dependency2.dll");
        }
    }
    public class DTree
    {
        public List<DTreeBranch> SubBranches { get; set; }
        public string BranchName { get; set; }
        public DTree() { SubBranches = new List<DTreeBranch>(); }
        public DTreeBranch AddChildren(string[] childElements, DTreeBranch branch)
        {
            DTreeBranch childBranch;
            foreach (string element in childElements)
            {
                childBranch = new DTreeBranch();
                childBranch.BranchName = element;
                branch.SubBranches.Add(childBranch);
                var query = from q in childElements
                            where q != childBranch.BranchName
                            select q;
                AddChildren(query.ToArray<string>(), childBranch);
            }
            return branch;
        }
        public void GrowTree(string[] pathElements, List<DTreeBranch> Branches)
        {
            DTreeBranch result = Branches.Find(delegate(DTreeBranch b)
            {
                return b.BranchName == pathElements[0];
            });

            if (result == null)
            {
                DTreeBranch newRootBranch = new DTreeBranch();
                newRootBranch.BranchName = pathElements[0];
                Branches.Add(newRootBranch);
                GrowTree(pathElements, Branches);
            }
            else
            {
                var query = from q in pathElements
                            where q != result.BranchName
                            select q;
                DTreeBranch childBranch = AddChildren(query.ToArray<string>(), result);
                Branches.Add(childBranch);
            }
        }
    }
    public class DTreeBranch
    {
        public List<DTreeBranch> SubBranches { get; set; }
        public string BranchName { get; set; }
        public DTreeBranch()
        {
            SubBranches = new List<DTreeBranch>();
        }
    }
}

Главное, чтобы на выходе было всего два слоя.Я предполагаю, что я говорю, что новые элементы добавляются в глубину, а не в широту, и я не знаю, как эффективно справиться с этим.Я также думаю, что у меня больше кода, чем мне нужно.

Заранее спасибо.

Ответы [ 2 ]

1 голос
/ 21 февраля 2012

Я получил примерно то же, что и Эндрю:

с использованием System;using System.Collections.Generic;using System.Collections.ObjectModel;используя System.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        public static void Main(String[] args)
        {
            var filePaths = new List<string> {@"ProgramDir\InstallDir\Module1\mod1pack1.exe", @"ProgramDir\InstallDir\Module1\mod1pack2.exe", @"ProgramDir\InstallDir\Module2\mod2pack1.exe", @"ProgramDir\InstallDir\Module1\SubModule1\report1.rpt", @"SystemDir\DependencyDir\dependency1.dll", @"SystemDir\DependencyDir\dependency2.dll"};
            var nodes = Parse(filePaths.ToArray());
            foreach (var node in nodes)
                Console.Out.WriteLine(node.ToString());
            Console.ReadLine();
        }

        public static IEnumerable<Node> Parse(params String[] paths)
        {
            var roots = new NodeSet();
            foreach (var path in paths)
            {
                var pathSplit = path.Split('\\');
                Node current = null;
                foreach (var pathElement in pathSplit)
                {
                    var currentRoots = (current == null) ? roots : current.Children;
                    if (currentRoots.Contains(pathElement))
                        current = currentRoots[pathElement];
                    else
                        currentRoots.Add(current = new Node(pathElement));
                }
            }
            return roots;
        }

        public class Node
        {
            public String Name { get; private set; }
            public NodeSet Children { get; private set; }

            public Node(String name)
            {
                if (String.IsNullOrWhiteSpace(name)) throw new ArgumentNullException("name");
                Name = name;
                Children = new NodeSet();
            }

            public override string ToString() { return ToString(1); }

            private String ToString(Int32 indent)
            {
                var indentStr = Environment.NewLine + new string('\t', indent);
                return Name + (Children.Count == 0 ? "" : indentStr + String.Join(indentStr, Children.Select(c => c.ToString(indent + 1)).ToArray()));
            }
        }

        public class NodeSet : KeyedCollection<String, Node> {
            protected override string GetKeyForItem(Node item) { return item.Name; }
        }
    }
}
1 голос
/ 21 февраля 2012

Я не совсем уверен, каковы наши цели, но простой рекурсивный анализ сделает это довольно легко. Написал это и надеюсь, что это поможет. Вы можете сделать это значительно более интересным, если хотите, с помощью DTrees и подветвлений, или отдельных коллекций для файлов и каталогов и т. Д. Я не совсем понимаю, для чего весь этот код существует. Если это имеет какое-то отношение к WIX, извините;) И вы всегда можете использовать что-то подобное, чтобы разобрать это в дереве, а затем преобразовать это разумно в другой формат.

  • предполагается, что нет повторяющихся конечных узлов (имен файлов).
  • если это не так, просто добавьте проверку работоспособности, как для каталогов.

Основной класс "Узел" -

public class Node
{
    public string Name { get; set; }
    public bool IsDirectory { get; set; }
    public List<Node> Children = new List<Node>();

    internal void AddChildren(string f)
    {
        var dirs = Path.GetDirectoryName(f);
        if (string.IsNullOrEmpty(dirs))
        {
            // we are adding a file
            var file = Path.GetFileName(f);
            Children.Add(new Node {Name = file, IsDirectory = false});
        }
        else
        {
            // we are adding a directory
            var firstDir = dirs.Split(Path.DirectorySeparatorChar)[0];
            var childNode = Children.FirstOrDefault(d => d.Name == firstDir);
            if (childNode == null)
            {
                childNode = new Node {Name = firstDir, IsDirectory = true};
                Children.Add(childNode);
            }

            var subPath = f.Substring(firstDir.Length + 1);
            childNode.AddChildren(subPath);
        }
    }
}

Называть это просто, вот так:

var filePaths = new List<string> { 
    @"ProgramDir\InstallDir\Module1\mod1pack1.exe",
    @"ProgramDir\InstallDir\Module1\mod1pack2.exe",
    @"ProgramDir\InstallDir\Module2\mod2pack1.exe",
    @"ProgramDir\InstallDir\Module1\SubModule1\report1.rpt",
    @"SystemDir\DependencyDir\dependency1.dll",
    @"SystemDir\DependencyDir\dependency2.dll",
};

var node = new Node { Name = "Root", IsDirectory = true };
foreach (var f in filePaths )
{
    node.AddChildren(f);
}

Распечатка (с отступом на уровень, дает мне это)

public static void PrintNode(Node node, int indent)
{
    if (indent > 0) // don't print out root directory (level 1). 
    {
        var ending = node.IsDirectory ? Path.DirectorySeparatorChar.ToString() : "*";
        Console.WriteLine("{0}{1}{2}", new string('\t', indent - 1), node.Name, ending);
    }
    node.Children.ForEach(n => PrintNode(n, indent + 1));
}

ProgramDir\
    InstallDir\
            Module1\
                    mod1pack1.exe*
                    mod1pack2.exe*
                    SubModule1\
                            report1.rpt*
            Module2\
                    mod2pack1.exe*
SystemDir\
    DependencyDir\
            dependency1.dll*
            dependency2.dll*
...