Из файла пути к уникальной структуре данных

Я читаю из файла список путей. Я хочу сохранить их во встроенной структуре Java, которая может автоматически удалять дубликаты. Под дубликатами я имею в виду, если у меня есть /usr/bin а потом добавляю /usr bin папка должна быть удалена, потому что она "содержится" внутри usr папка. Я читаю файл последовательно, поэтому я предпочел бы не проверять все данные дважды, если это возможно.

Пример кода:

UnknownType<Path> database;
BufferedReader reader = new BufferedReader(new FileReader(new File("db.txt")));

String line;
while ((line = reader.readLine()) != null) {
    Path path = Paths.get(line).toRealPath();
    database.add(path);
}

Пример файла:

/usr/bin
/usr
/dev
/dev/sda1
/dev/sda2
/home/user/Desktop/file.txt
/home/user/Documents/file2.txt
/home/user/Documents/file3.txt

Ожидаемый результат:

data structure containing paths: 
/usr
/dev
/home/user/Desktop/file.txt
/home/user/Documents/file2.txt
/home/user/Documents/file3.txt

3 ответа

Решение

Основанное на дереве решение (возможно, более эффективное):

class Database {

  public void add(String p) {
    root.add(Arrays.asList(p.split("\\\\|/")), 0);
  }

  public void addAll(Collection<? extends String> list) {
    for (String p : list)
    add(p);
  }

  public List<String> getPathsList() {
    ArrayList<String> list = new ArrayList<>();
    root.listPaths(list, "");
    return list;
  }

  PathNode root = new PathNode("");

  static class PathNode {

    public final String name;
    public Map<String, PathNode> children = new HashMap<>();

    public PathNode(String name) {
      this.name = name;
    }

    public boolean isLeaf() {
      return children.size()==0;
    }

    public boolean isRoot() {
      return name.isEmpty();
    }

    public void add(List<String> path, int i) {
      String childName = path.get(i);
      PathNode child = children.get(childName);

      if (child != null) {
        if (path.size()-i <= 1) child.children.clear();
        else child.add(path, i+1);
      } else if (!isLeaf() || isRoot()) {
        PathNode node = this;
        for (; i < path.size(); i++) {
          String key = path.get(i);
          node.children.put(key, node = new PathNode(key));
        }
      }
    }

    public void listPaths(ArrayList<String> list, String prefix) {
      for (PathNode child : children.values()) {
        if (child.isLeaf()) list.add(prefix+child.name);
        else child.listPaths(list, prefix+child.name+File.separator);
      }
    }

  }

}

Тест для проверки правильности: http://ideone.com/cvqEVT

Эта реализация будет принимать пути Windows и Unix при работе на любой платформе. Пути, возвращаемые Database.getPathsList() все равно будет использовать разделитель файлов ОС; Вы можете изменить это, изменив File.separator в Database.PathNode.listPaths (последняя строка реального кода).

Простое решение:

class Database {

  public void add(Path p) {
    for (int i = 0; i < paths.size(); i++) {
      Path p2 = paths.get(i);
      if (p2.startsWith(p)) {
        // replace with new path
        paths.set(i, p);
        return;
      }
      if (p.startsWith(p2)) {
        // don't add this new one
        return;
      }
    }
    // else, add the new one
    paths.add(p);
  }

  ArrayList<Path> paths = new ArrayList<>();

}

LinkedList реализация:

class Database {

  public void add(Path p) {
    for (ListIterator<Path> it = paths.listIterator(0); it.hasNext();) {
      Path p2 = it.next();
      if (p2.startsWith(p)) {
        // replace with new path
        it.set(p);
        return;
      }
      if (p.startsWith(p2)) {
        // don't add this new one
        return;
      }
    }
    // else, add the new one
    paths.add(p);
  }

  LinkedList<Path> paths = new LinkedList<>();

}
static ArrayList<Path> paths = new ArrayList<Path>();

public static void main (String[]args) { 
    add(Paths.get("/usr/bin"));
    add(Paths.get("/usr"));
    add(Paths.get("/dev"));
    add(Paths.get("/dev/sda"));
    add(Paths.get("/home/user/Desktop/file.txt"));
    System.out.println(paths.toString());
} 

public static void add(Path path){
    // get root
    String firstDir = path.subpath(0, 1).toString();
    // check all known paths
    for (int q = 0; q < paths.size(); q++){
        Path p = paths.get(q);
        // get root of saved path
        String pFirstDir = p.subpath(0, 1).toString();

        // do they have the same root path
        if (pFirstDir.equals(firstDir)){
            // the new path needs to have less folders otherwise return
            if (path.getNameCount()>p.getNameCount()){
                return;
            }

            // set the new path and return
            paths.set(q, path);
            return;
        }
    }
    // no paths found taht match so add
    paths.add(path);
}

напечатает:

[\usr, \dev, \home\user\Desktop\file.txt]
Другие вопросы по тегам