我试图找出一个针对以下问题的最佳解决方案(用Java):
在第一次传递某些数据时,我会计算项目的出现次数。基本上,我从项ID到整数创建一个HashMap,并在每次看到项的出现时递增整数。所以基本上,我有一个来自itemID的Map<Long,Integer>
来计算。
现在,我在这张地图中需要的是按计数排序的前n项ID。
显然HashMap不是这里的最佳数据结构。有什么想法吗?
这是我正在做的一些数据挖掘工作,所以不是一个小问题......
答案 0 :(得分:4)
实际上,HashMap在这里是一个合理的解决方案,因为你必须累积总数。在你知道所有项目的计数之前,你无法用它来快捷方式找到前N个项目。
拥有HashMap之后,有几种方法可以做。如果数据相对较小,则创建一个itemId和count对数组,并按降序排序。然后选择前N项。
如果你有很多项目(成千上万),你得到计数后使用最小堆可能会更快,这个想法是你把前N个项放入最小堆然后只插入一个item如果其计数大于最小堆中的最小项。
当你进行添加时,你可以按顺序保持顺序,但每次增加一个计数器时,你必须从集合中删除它并重新插入它。你最好在HashMap中积累东西,在那里可以很容易地通过ID查找内容,然后进行后处理以按计数应用排序。
答案 1 :(得分:2)
我会在计算后对结果进行排序。
Map<Item,Integer> map = new HashMap<Item, Integer>();
... (fill the map, counting the occurences)
List<Map.Entry<Item, Integer>> list = new ArrayList<Map.Entry<Item, Integer>>(map.size());
list.addAll(map.entrySet());
Collections.sort(list, new Comparator<Map.Entry<Item, Integer>>() {
public int compare(Map.Entry<Item, Integer>> left, Map.Entry<Item, Integer>> right) {
// "-" to invert the order
return - left.getValue().compareTo(right.getValue());
}
});
现在list
是一个列表,其中的项目按计数排序(降序),.subList(0, n)
将为您提供前n个。
如果你的n
比项目总数小得多,那么这不是最优的 - 我认为有一个更好(但更复杂)的算法只能获取最好的一些无序列表。
答案 2 :(得分:0)
一个明显的答案是使用SortedMap。确保新创建的地图的可比属性使顶部项目编号为1,您可以从中获取第一个元素。
答案 3 :(得分:0)
我认为如果您希望能够获取ID,计算并仍然维护Map结构,则需要创建一个类来封装数据。
public class DataPair implements Comparable<DataPair> {
private long id;
private Integer count;
//Getters and setters
public void increaseCount() {
count++;
}
public int compareTo(DataPair dp) {
return this.count.compareTo(dp.count);
}
}
然后就像你一直在使用的地图一样:
Map<long, DataPair> m = new HashMap<long, DataPair>()
然后,当您需要按计数排序时,您可以获取值并对其进行排序,同时保持按ID获取当前计数的能力。
List<DataPair> list = new ArrayListM<DataPair>(m.values());
Collections.sort(list);
然后你将获得你的排序计数,并且仍然能够获得ID。
答案 4 :(得分:0)
您可以按如下方式排序[按值排序]的排序地图:
创建一个类Profile
,它将保存您的数据和计数[用于临时目的]。
您的个人资料类将如下所示:
class Profile
{
public String data;
public Integer value;
public int getValue()
{
return value;
}
}
根据值排序的方法如下:
public Map<String, Integer> sortMapByValues(final Map<String, Integer> passedMap)
{
List<Profile> tuples = new LinkedList<Profile>();
Iterator<String> it = passedMap.keySet().iterator();
while (it.hasNext())
{
String key = it.next();
Integer val = passedMap.get(key);
tuples.add(new Profile(key, val));
}
Collections.sort(tuples, new ProfileComparator());
Map<String, Integer> sortedMap = new LinkedHashMap<String, Integer>();
for (int i = 0; i < tuples.size(); i++)
{
sortedMap.put(tuples.get(i).getKey(), tuples.get(i).getValue());
}
return sortedMap;
}
现在您只需要一个Comparator实现。
您的ProfileComparator类将如下所示:
public final class ProfileComparator implements Comparator<Profile>
{
public int compare(final Profile n1, final Profile n2)
{
if (n1.getValue() > n2.getValue())
{
return -1;
}
if (n2.getValue() > n1.getValue())
{
return 1;
}
return 0;
}
}
答案 5 :(得分:0)
也许TreeMap是更可选的解决方案。
http://docs.oracle.com/javase/6/docs/api/java/util/TreeMap.html