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

时间:2017-09-20 11:05:25

标签: java sorting unique treemap

我有TreeMap<Long, String>包含<FileSize, FileName>元组,因为我需要按文件大小对其进行排序。订购效果很好。

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

我只是尝试将递增计数器值添加到TreeMap键,方法是将TreeMap更改为TreeMap<String, String>并按<fileSize#counter, fileName>填充键。然后问题是密钥的排序,因为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)排序?

谢谢!

5 个答案:

答案 0 :(得分:4)

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

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

上述内容将保留订单,并将文件名列表保存为文件大小

答案 1 :(得分:3)

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

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);
   }
}

答案 2 :(得分:0)

无论

  • 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<>();

答案 3 :(得分:0)

 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);
    }
});

答案 4 :(得分:0)

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

    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的类,一个是大小,另一个是唯一的数字,或者包含大小和名称的类,并使用两个字段正确编写比较器
  3. 使用MultiSet(例如来自Guava或Apache)
  4. 使用TreeSet<Long, Set<String>>并在一个集合中存储相等长度的文件名(这通常是如何在内部实施MultiSets)