Reputation: 83
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
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
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
Reputation: 1382
I think the problem is in your equals method, when you do this check:
if (count != other.count)
return false;
Upvotes: 0
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
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
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