计算项目的出现次数

时间:2011-02-22 20:15:35

标签: java algorithm data-mining

我试图找出一个针对以下问题的最佳解决方案(用Java):

在第一次传递某些数据时,我会计算项目的出现次数。基本上,我从项ID到整数创建一个HashMap,并在每次看到项的出现时递增整数。所以基本上,我有一个来自itemID的Map<Long,Integer>来计算。

现在,我在这张地图中需要的是按计数排序的前n项ID。

显然HashMap不是这里的最佳数据结构。有什么想法吗?

这是我正在做的一些数据挖掘工作,所以不是一个小问题......

6 个答案:

答案 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