Nataraj
Nataraj

Reputation: 83

Updating the objects of a Set in Java

I am trying to read from a file and count how many times each string appears in the file. I am using a HashSet on the Object Item which i have created as follows :

Now in my main i am trying to read the file and add each String in the file to my set. Also while adding i am trying to increment the count of an item in the set which is appearing more than once. Here's my implementation for that :

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

}

For an input file like this :

chair table teapot
teapot book table
chair floor ceiling
wall chair floor

it is giving an output as follows :

wall appears 1 times
book appears 1 times
table appears 2 times
floor appears 2 times
teapot appears 2 times
chair appears 1 times
ceiling appears 1 times
chair appears 2 times

Here the set is having duplicate elements which i don't want. What is the correct way to update the objects inside a set?

Upvotes: 0

Views: 1707

Answers (6)

Josh
Josh

Reputation: 707

Your Item class uses the count field in its definition of equals and hashCode. This means that when you call set.contains(i) for the second occurrence of the string, contains will return true since count==1. You then increment count, and when you call set.contains(i) for the third occurrence of the string contains will return false, since the count of the Item in the set does not match the count of the Item you are passing to contains.

To fix this, you should change your definition of equals and hashCode to consider only the string and not the count.

This implementation will work, but is overly complex. You could simply create a Map<String, Integer> and increase the Integer (count) each time you see a new occurrence of the string.

Upvotes: 1

Conffusion
Conffusion

Reputation: 4475

Have you considered using a HashMap for your problem: put the name in the key and the counter in the value. This way you don't need an Item class at all.

Upvotes: 0

Michał Schielmann
Michał Schielmann

Reputation: 1382

I think the problem is in your equals method, when you do this check:

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

Upvotes: 0

Smutje
Smutje

Reputation: 18143

HashSet uses hashCode and equals to determine identity, so you should change hashCode and equals to work with the name only when you don't want to include the count of items in the test for equality:

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

Upvotes: 0

Yogesh Prajapati
Yogesh Prajapati

Reputation: 4870

i think this'll help you.

Create list of all keywords, and use code below.

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

output

b: appears 1 time
a: appears 2 time

Upvotes: 2

Siva Kumar
Siva Kumar

Reputation: 2006

Your Implementation is right. But your Item class equals method has only problem.

In equals method you have used count variable also. But name is only the unique field in that class. You have used count+name as unique. So it will create problem.

Upvotes: 0

Related Questions