从地图中获取前5个值

时间:2014-09-27 22:28:00

标签: java

我有一张这样的地图

Map<String, Integer> map = new HashMap<String, Integer>();

这将包含大量的推文,而我想要做的就是制作一些前5名的统计数据。

我现在拥有的是

int maxValueInMap=(Collections.max(map.values()));
for (Entry<String, Integer> entry : map.entrySet()) {                       
if (entry.getValue()==maxValueInMap) {
     name = entry.getKey();
}
}

这对于获取地图中数字1最高值的键/值非常有用,但我无法弄清楚我如何能够获得前五名的最高值并具有类似

的内容
int maxValueInMap=(Collections.max(map.values()));
for (Entry<String, Integer> entry : map.entrySet()) {                       
if (entry.getValue()==maxValueInMap) {
     name = entry.getKey();
     name2 = entry.getKey(2ndHighest);
     //so on
}
}

感谢任何帮助,谢谢。

修改

我发现这段代码的功能就像它希望的那样

public class Main {

public static void main(String[] args) {

    HashMap<String,Integer> map = new HashMap<String,Integer>();
    ValueComparator bvc =  new ValueComparator(map);
    TreeMap<String,Integer> sorted_map = new TreeMap<String,Integer>(bvc);

    map.put("a",10);
    map.put("b",6);
    map.put("c",6);
    map.put("d",56);
    map.put("e",54);
    map.put("f",32);
    map.put("g",1);

    System.out.println("unsorted map: "+map);
    sorted_map.putAll(map);
    System.out.println("results: "+sorted_map);
}
}

class ValueComparator implements Comparator<String> {

Map<String, Integer> base;
public ValueComparator(Map<String, Integer> base) {
    this.base = base;
}

public int compare(String a, String b) {
    if (base.get(a) >= base.get(b)) {
        return -1;
    } else {
        return 1;
    }
}
}

打印出来

unsorted map: {a=10, b=6, c=6, d=56, e=54, f=32, g=1}
results: {d=56, e=54, f=32, a=10, c=6, b=6, g=1}

但是我怎样才能从sorted_map而不是所有的部分中获得前5名?

2 个答案:

答案 0 :(得分:2)

您希望按值对项目进行排序,默认情况下,这不能在HashMapTreeMap中完成。

您应该考虑拥有自己的课程并使用TreeSet

class Entry implements Comparable<? extends Entry> {
  public final String name;
  public final Integer value;

  ..

  public int compareTo(Entry o) { return value == o.value ? o.name.compareTo(name) : o.value - value; }

  public boolean equals(Object o) {
    // equals consistent to compareTo (name and value equal for both entries)
  }
}

SortedSet<Entry> set = new TreeSet<Entry>();
set.add(...)

答案 1 :(得分:2)

这样做的简单方法是:

  • 将hashmap的条目集复制到数组
  • 对数组进行排序
  • 取前五个条目。

然而,排序步骤是O(N log N),如果N很大并且您需要重复获得前5个,那么这就是性能杀手......并且可以更新整数值(例如计数)。 / p>


如果您需要更好的性能,则需要更复杂的数据结构,以允许增量更新(以避免重新排序):

  • 从字符串到字符串/计数对的1对1映射
  • 按计数排序的字符串/计数对的有序集合

如果您将自己限制在标准集合类中,可以使用以下方法完成此操作:

  • 用于保留配对的自定义Pair课程。
  • 前向映射的HashMap<String, Pair>
  • 用于保持对顺序的TreeSet<Pair>
  • 一个(稳定的)比较器,主要通过Pair同一性对其进行排序。 (后者很重要。比较器不能将Pair个对象计为相同的计数,否则Pair个对象将被错误地删除为重复!)。

您记得的最后一件事是,如果您只更改TreeSet中的countPair将无法自动正确更新。相反,你需要:

  1. Pair
  2. 中删除TreeSet
  3. 更新count
  4. Pair添加回TreeSet
  5. 其余的是“只是编程”。 (但对我来说,现在编写,编译,测试等太复杂了:-))


    如果您正确执行上述操作,则添加或递增计数应为O(log N),并且查找前5个条目应为O(1)。但是,由于您使用它作为O(1)添加/增加的解决方案的替代品,如果N很大(足够)并且“前5”是相对的,这只是一个明显的性能获胜常见的操作。

    还值得注意的是,您还可以在M中未排序的N元素集合中获取前O(N log M)个元素。如果M是一个小常量,则会减少到O(N)。换句话说,它比在顶部简单版本中对条目集进行排序更好。 (小N也可能更快。)


    回答这个后续问题:

      

    但是我怎样才能从sorted_map中获得前5名,而不是所有的主语?

    创建一个迭代器,然后只调用next() 5次!

    但我还要注意,您找到的代码是 INCORRECT 。我强烈建议您自己编写代码并对其进行全面测试。 (或者将您的搜索限制在包含合适的单元测试套件的可信库中。)