Java:将字符串转换为树

时间:2012-01-31 17:29:00

标签: java tree

我有一个作为目录的字符串的排序列表,我需要将其显示为树。

例如,如果我有这些字符串:

"folder a/folder b/file 1"
"folder a/folder b/file 2"
"folder a/folder c"

我需要将它们显示为:

folder a
|- folder b
|  |- file 1
|  |- file 2
|- folder c

我正在考虑浏览列表并跟踪“父文件夹”(即第一个字符串的“文件夹a /文件夹b”)并构建树,具体取决于“父文件夹”是否为相同。回到父文件夹时,这似乎相当复杂,我想知道是否有人可以推荐一种更简单/更有效的方法来做到这一点?

首先迭代字符串并实际构建一个树,然后在显示它之前遍历树是否有帮助?值得注意的是,所有数据都保存为字符串(此树不会被保存),因此每次我想要显示它时都需要我构建树数据结构。

6 个答案:

答案 0 :(得分:6)

希望有所帮助。构建目录的整个结构。讽刺短名称和缺乏泛型。希望它更具可读性。

public static void main(String[] args) {
    ArrayList<String> listOfPaths = new ArrayList<String>();
    listOfPaths.add("folder a/folder b/file 1");
    listOfPaths.add("folder a/folder b/file 2");
    listOfPaths.add("folder a/folder c");

    TreeMap structure = new TreeMap();
    for (String path : listOfPaths) {
        String[] tmp = path.split("/", 2); // [ "folder a/", "folder b/file 1"]  for first loops step
        put(structure, tmp[0], tmp[1]);
    }

    print(structure, "");
}
private static void put(TreeMap structure, String root, String rest) {
    String[] tmp = rest.split("/", 2);

    TreeMap rootDir = (TreeMap) structure.get(root);

    if (rootDir == null) {
        rootDir = new TreeMap();
        structure.put(root, rootDir);
    }
    if (tmp.length == 1) { // path end
        rootDir.put(tmp[0], null);
    } else {
        put(rootDir, tmp[0], tmp[1]);
    }
}
private static void print(TreeMap map, String delimeter) {
    if (map == null || map.isEmpty())
        return;
    for (Object m : map.entrySet()) {
        System.out.println(delimeter + "-" + ((Map.Entry)m).getKey());
        print((TreeMap)((Map.Entry)m).getValue(), " |" + delimeter);
    }
}

答案 1 :(得分:4)

如果您只想打印树,可以查看此代码段。它输出你想要的东西。

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class StringTree {

    public static void main(String[] args) {

    List<String> folders = new ArrayList<String>();
    folders.add("folder a/folder b/file 1");
    folders.add("folder a/folder b/file 2");
    folders.add("folder a/folder c");
    // for a non-lexically sorted folder list
    Collections.sort(folders);

    Map<Integer, String> map = new HashMap<Integer, String>();
    for (String path : folders) {
        String[] parsedPath = path.split("/");
        boolean newBranch = false;
        for (int i = 0; i < parsedPath.length; i++) {
        newBranch |= !parsedPath[i].equals(map.get(i));
        if (newBranch) {
            map.put(i, parsedPath[i]);
            print(i, parsedPath[i]);
        }
        }
    }
    }

    private static void print(int level, String item) {
    String tab = "";
    for (int i = 0; i < level; i++)
        tab = tab + ((i == 0) ? "| " : "|- ");
    System.out.println(tab + item);
    }

}

更新:修正了数据错误:

folders.add("folder a/folder b/file 1");
folders.add("folder b/folder b/file 1");

答案 2 :(得分:1)

我认为很大程度上取决于你的最终目标。如果只是打印出数据,或者您需要处理数据,或者需要以算法方式对其进行操作。

我的直觉就是使用LinkedHashMap完成所有这一切,并且基本上将它作为地图地图的地图等等...但是因为你有两个干净利落地这样做会有点棘手地图的不同可能值 - 文件夹和文件。请注意,使用LinkedHashMap是为了在插入数据时保持数据的顺序。如果您想要它排序或随机顺序,那么您可以选择其他实现。

基本上,我会将其视为以下(伪代码)

public interface DirectoryEntry{
  boolean isFile;
  boolean isFolder;
}

public class Folder implements DirectoryEntry{
    public boolean isFile(){ return false;}
    public boolean isFolder(){ return true;}

    private Map<String, DirectoryEntry> entries = new LinkedHashMap<String, DriectoyrEntry>();

    public Map<String, DirectoryEntry>getEntries(){ return entries;}
    public void addFile( String filename ){ entries.put( filename, new File();}
    public void addFolder( String foldername){entries.put(foldername, new Folder();}
}

public class File implements DirectoryEntry{
    public boolean isFile(){ return true;}
    public boolean isFolder(){ return false;}
 }

然后构建树(你也可以递归地执行此操作):

Map<String, DirectoryEntry> entries = new LinkedHashMap<String, DirectoryEntry>()

while( !end of list){
  Map entry = entries;

  1. Split string on '/'
  2. foreach( token ){
         if file
        entries.put( token, new File() );
         else{
        if( !entry.containsKey( token ) )
           entry.put(token, new Folder );

        // use the folder map for any sub-folders/files
        entry = ((Folder)entry.get( token )).getEntries();
         }
  }
}

然后,您可以浏览最终列表并根据需要使用它。我有意创建基本的文件和文件夹,但如果您有/需要,可以在那里添加其他元数据/信息。

请记住,这只是一个选项,可以让您了解如何解析/映射文件/文件夹,但并不是一个功能性解决方案。

至于是否更容易先解析和打印,就像我说的那样,这完全取决于你希望用最终数据集实现的目标。但我的直觉就是解析所有内容,然后展示你所解析的内容,以确保你所展示的内容是你“理解”并将会操纵的内容。

答案 3 :(得分:0)

基本上,它都是从'Root'开始的。 你能做的是:

while(!End of List)
{
    tempNode = Root;
    1. Resolve each line into tokens (with '/' as delimiter)
    2. while(hasMoreTokens())
       {
           3. Check if nextToken() is the child of tempNode
           4. If not, create node with nextToken(), continue till all tokens of line are exhausted.
           5. If yes, go to tempNode.nextToken(). Go to step 3.
       }
}

这样,每次遍历列表的每一行时都会创建树。

答案 4 :(得分:-1)

最好先构建树然后再显示,因为这可以适应以后的任何更改。您可以创建一个Node对象,如

class Node{
  // level deep of this node, can use to format the display like
  // 4 level deep will have four leading spaces
  private int level;
  // the actual text
  private String text;
  // Parent Node for this, can be null if this is the root node, set this when creating
  private Node parent;
  // children of this Node
  private List<Node> children; 
  // Getters and setters for the above properties....
}

答案 5 :(得分:-1)

我有一个树实现,可以用这么简单的代码来实现它:

PathTreeBuilder.Funnel<String, String> urlFunnel = new PathTreeBuilder.Funnel<String, String>() {
    @Override
    public List<String> getPath(String value) {
        return Lists.newArrayList(value.split("/"));
    }
};
PathTreeBuilder<String, String> builder = new PathTreeBuilder<String, String>(urlFunnel);
List<Tree<String>> build = builder.build(urls);
build.toStringTree();

希望它会对某人有所帮助。