生成唯一键以避免在 TreeMap 中覆盖

Generate unique key to avoid overwriting in TreeMap

我有一个 TreeMap<Long, String>,其中包含 <FileSize, FileName> 的元组,因为我需要按文件大小对其进行排序。订购完美无缺。

现在我遇到了一个问题,一个与 Map 中已经存在的另一个文件大小相同的新文件会用这个新文件名覆盖旧条目。

我只是试图通过将 TreeMap 更改为 TreeMap<String, String> 并用 <fileSize#counter, fileName> 填充键来向 TreeMap 键添加一个递增的计数器值。然后问题是键的顺序,因为 String 例如9#1 会出现在 89#190#1 之间,这是错误的,因为 fileSize 只有 9(因此应该出现在 89 和 90 之前)!

然后我写了一个自定义的 Comparator 它能够通过 fileSize 再次排序(通过删除带有计数器值的第二部分),但是如果密钥的第一部分 (fileSize) 相同(独立于 #counter 值)。

这是我的代码:

TreeMap<String, String> fileNamesAndSizes = new TreeMap<String, String>(new Comparator<String>() {
    public int compare(String o1, String o2) {
        Long key1 = Long.valueOf(o1.split("#")[0]);
        Long key2 = Long.valueOf(o2.split("#")[0]);

        return key1.compareTo(key2);
    }
});

如何在我的 TreeMap 中获取唯一键而不覆盖现有值并获得正确的(升序 fileSize)排序?

谢谢!

我会尝试将它们存储在这样的结构中:

TreeMap<Long, Set<String>> map; //Long file Size, Set <-- file name(s)

现在添加一个新文件:

if(!map.contains(key)){  //key the size of the file
 Set<String> set = new HashSet<String>();
 map.put(key,set);
}
map.get(key).add(set);

要检索您需要遍历每个值条目:

for(Map<Long,Set<String>> entry  : map.entrySet()){

   for(String s : entry.getValue()){
    System.out.println(entry.getKey() + " : " + s);
   }
}

两者都

  • file name 应该是唯一键(Map<String, Long>),或者
  • (file name, file size) (Set<Pair<String, Long>>)。

文件名

SortedMap<String, Long> fileNamesAndSizes = new TreeMap<>();

元组(文件名,文件大小)

class FileInfo implements Comparable<FileInfo> {
    public final String name;
    public final long size;
    public FileInfo(String name, long size) {
        this.name = name;
        this.size = size;
    }
    @Override
    public int compareTo(FileInfo other) {
        ...
    }
}
OrderedSet<FileInfo> fileNamesAndSizes = new TreeSet<>();

尝试使用值为列表的地图,如下所示:

TreeMap<String, List<String>> map; // like <FileSize, List<FileName>>

以上将保持顺序并保存文件名的列表,文件大小

 static int i = 1 ;
    TreeMap<String, String> fileNamesAndSizes = new TreeMap<String, String>(new Comparator<String>() {
    public int compare(String o1, String o2) {
        Long key1 = Long.valueOf(o1.split("#")[i]);
        i += 1;
        // somthing like this 
        return key1.compareTo(key2);
    }
});

您的比较器需要比较两个字段:

    public int compare(String o1, String o2) {
        String[] o1parts = o1.split("#");
        String[] o2parts = o2.split("#");
        long key1 = Long.parseLong(o1parts[0]);
        long key2 = Long.parseLong(o2parts[0]);
        int cmp = Long.compare(key1, key2);
        if (cmp != 0)
            return cmp;

        return Long.compare(Long.parseLong(o1parts[1]), Long.parseLong(o2parts[1]));
    }

存在各种更可取的选择:

  1. 首先创建零填充字符串,然后使用字符串的自然排序而不是自定义比较器
  2. 而不是字符串,使用包含两个 long 的 class,一个是大小,另一个是唯一数字,或者 class 包含大小和名称,并编写比较器适当地使用这两个字段
  3. 使用 MultiSet(例如来自 Guava 或 Apache)
  4. 使用 TreeSet<Long, Set<String>> 并在一个集合中存储等长的文件名(这就是 MultiSet 通常在内部实​​现的方式)