在Java中更新Set的对象

时间:2014-08-18 10:25:39

标签: java collections

我正在尝试从文件中读取并计算每个字符串在文件中出现的次数。我在对象项上使用HashSet,我创建如下:

现在在我的主要部分我试图读取文件并将文件中的每个字符串添加到我的集合中。另外,在添加时我试图增加集合中多次出现的项目的计数。这是我的实现:

package pack;

public class Item {

    public String name;
    public int count=1;
    public Item(String name)
    {
        this.name = name;
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + count;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Item other = (Item) obj;
        if (count != other.count)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }

}

对于这样的输入文件:

椅子茶壶
茶壶书桌
椅子地板天花板
墙椅底板

它输出如下:

墙出现1次
书出现1次
表出现2次
地板出现2次
茶壶出现2次
椅子出现1次
天花板出现1次
椅子出现2次

这里的集合具有我不想要的重复元素。更新集合中对象的正确方法是什么?

6 个答案:

答案 0 :(得分:2)

我认为这对你有所帮助。

创建所有关键字的列表,并使用以下代码。

public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("a");
        list.add("b");
        list.add("a");

        // get all Unique keywords 
        Set<String> set = new HashSet<String>(list);
        for(String keyword: set){
            System.out.println(keyword + ": " + Collections.frequency(list, keyword));
        }
    }

输出

b: appears 1 time
a: appears 2 time

答案 1 :(得分:0)

您的实施是对的。但是你的Item类equals方法只有问题。

在equals方法中,您也使用了count变量。但名称只是该类中的唯一字段。您已使用count + name作为唯一。所以它会产生问题。

答案 2 :(得分:0)

HashSet使用hashCodeequals来确定身份,因此您应该更改hashCodeequals才能使用该名称想要在测试中包含相等的项目数:

package pack;

public class Item {

    public String name;
    public int count=1;

    public Item(String name)
    {
        this.name = name;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Item other = (Item) obj;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }
}

答案 3 :(得分:0)

我认为问题在于你的equals方法,当你做这个检查时:

if (count != other.count)
        return false;

答案 4 :(得分:0)

您的Item类在其equals和hashCode的定义中使用count字段。这意味着当您为第二次出现的字符串调用set.contains(i)时,contains将返回true,因为count == 1。然后你增加计数,当你调用set.contains(i)第三次出现的字符串时,contains将返回false,因为集合中Item的计数与{{1的计数不匹配你要传递给包含。

要解决此问题,您应该更改equals和hashCode的定义,以仅考虑字符串而不考虑计数。

此实现可行,但过于复杂。您可以简单地创建一个Item,并在每次看到新出现的字符串时增加整数(计数)。

答案 5 :(得分:0)

您是否考虑过为您的问题使用HashMap:将名称放在键中,将计数器放在值中。这样你根本不需要一个Item类。