Java Collection removeAll not removing a thing - java

So I have an old list, a new list, and a unique list. I read in the data from each list (old/new) and make a bunch of objects from my class file. Then I add the newList to the unique, followed by my removing the old list to determine the unique Users.
CLASS
public class User {
private String fName;
private String mInitial;
private String lName;
private String age;
private String city;
private String state;
... // set and get methods
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((age == null) ? 0 : age.hashCode());
result = prime * result + ((city == null) ? 0 : city.hashCode());
result = prime * result + ((fName == null) ? 0 : fName.hashCode());
result = prime * result + ((lName == null) ? 0 : lName.hashCode());
result = prime * result
+ ((mInitial == null) ? 0 : mInitial.hashCode());
result = prime * result + ((state == null) ? 0 : state.hashCode());
return result;
}
#Override
public boolean equals(Object o) {
if(o == null) return false;
if (getClass() != o.getClass()) return false;
User other = (User) o;
if(this.fName != other.fName) return false;
if(! this.mInitial.equals(other.mInitial)) return false;
if(! this.lName.equals(other.lName)) return false;
if(! this.age.equals(other.age)) return false;
if(! this.city.equals(other.city)) return false;
if(! this.state.equals(other.state)) return false;
return true;
}
}
MAIN
try {
// List creation (new, old, unique)
List<User> listNew = new ArrayList<User>();
List<User> listOld = new ArrayList<User>();
Collection<User> listUnique = new HashSet<User>();
// Read the files in with while loop,
// ...
// Put them in their respective list
// ...
listUnique.addAll(listNew);
System.out.println("Junk... " + listUnique.size());
listUnique.removeAll(listOld);
// Checking the sizes of lists to confirm stuff is working or not
System.out.println(
"New: \t" + listNew.size() + "\n" +
"Old: \t" + listOld.size() + "\n" +
"Unique: " + listUnique.size() + "\n"
);
}
catch { ... }
OUTPUT
Junk... 20010
New: 20010
Old: 20040
Unique: 20010
So basically it is adding the content to the list but the removeAll doesn't work. Could this be a problem with my hashCode() in my User Class file? I just cannot figure out why it's not working. (Note: I auto generated my hashCode in the class file, not sure if that's a bad idea)
Thanks for any help!

as Takendarkk pointed out. It might be because you are checking references instead of value in case of string name. If the origin of name is different (they have different references) they might be treated unequal even if they have same value.

Related

Is there any way to find the duplicate values i.e ArrayList from a hash map?

For eg:-
I have declared a hashMap in the form of:
Map<String, List<Tracks>> dupItems = new LinkedHashMap();
Tracks is a model class that contains name, address, and age.
and I added items in a Tracks
and I added Items as:-
dupItems.add("Project",tracks);
dupItems.add("Report",tracks);
and what I want is a list of duplicate tracks i.e how can I match the items on the basis of values of tracks i.e all values have to be similar. same name, same address, and same age.
If you are looking for the duplicate map values, that is, duplicate lists of Tracks:
One way you can do this is iterate over the values, putting them all in a Set data structure. If you find that the value was already in the set, then it's a duplicate, and you add it to a separate data structure that keeps a record of the duplicate values:
Set<List<Tracks>> findDuplicateValues(Map<String, List<Tracks>> dupItems) {
Set<List<Tracks>> allValues = new HashSet<>();
Set<List<Tracks>> duplicateValues = new HashSet<>();
for (List<Tracks> value : dupItems.values()) {
if (!allValues.add(value)) {
// It's a duplicate!
duplicateValues.add(value);
}
}
return duplicateValues;
}
For this to work reliably, the Tracks class has to implement the equals and hashCode methods. Comparing two objects with the same values using the equals method should return true.
On the other hand, if you are looking for the duplicate Tracks values, no matter which map value list contains them:
you just need to add a loop to the previous method:
Set<List<Tracks>> findDuplicateValues(Map<String, List<Tracks>> dupItems) {
Set<List<Tracks>> allValues = new HashSet<>();
Set<List<Tracks>> duplicateValues = new HashSet<>();
for (List<Tracks> value : dupItems.values()) {
for (Tracks value : values) {
if (!allValues.add(value)) {
// It's a duplicate!
duplicateValues.add(value);
}
}
}
return duplicateValues;
}
I'm assuming we search for duplicate Tracks instances.
public Set<Tracks> findDuplicates(Map<String, List<Tracks>> dupItems) {
Set<Tracks> all = new HashSet<>();
return dupItems.values().stream()
.flatMap(list -> list.stream()) // build a single list of Tracks
.filter(t -> !all.add(t)) // add track to all set but only continue if duplicate
.collect(Collectors.toSet()); // store the remaining tracks in a set (to avoid duplicates in the result
}
A Set will check on duplicates only if the equals() function is correctly implemented.
My eclipse editor generated :
private static class Tracks {
String name;
String address;
int age;
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((address == null) ? 0 : address.hashCode());
result = prime * result + age;
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;
Tracks other = (Tracks) obj;
if (address == null) {
if (other.address != null)
return false;
} else if (!address.equals(other.address))
return false;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
You can also have a look at Apache Commons EqualsBuilder

How to compare objects from a same class based on their attributes?

I have this objects:
COSTOS Costos = new COSTOS(1781, 359.13, "BISAG.SUP.PUER.TRA.I", "67550T9AT00ZZ");
COSTOS Herramienta = new COSTOS(1795, 299.11, "BISAG.INF.PUER.TRA.I", "67960T2MT02ZZ");
And this is my class:
public class COSTOS implements Comparable<COSTOS>{
public int referencia;
public double monto;
public String descripcion;
public String NumeroParte;
//Constructor
//getters setters
Also, i implemented HashCode and equals:
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((NumeroParte == null) ? 0 : NumeroParte.hashCode());
result = prime * result + ((descripcion == null) ? 0 : descripcion.hashCode());
long temp;
temp = Double.doubleToLongBits(monto);
result = prime * result + (int) (temp ^ (temp >>> 32));
result = prime * result + referencia;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
COSTOS other = (COSTOS) obj;
if (NumeroParte == null) {
if (other.NumeroParte != null)
return false;
} else if (!NumeroParte.equals(other.NumeroParte))
return false;
if (descripcion == null) {
if (other.descripcion != null)
return false;
} else if (!descripcion.equals(other.descripcion))
return false;
if (Double.doubleToLongBits(monto) != Double.doubleToLongBits(other.monto))
return false;
if (referencia != other.referencia)
return false;
return true;
}
How could i implement a method that could print all the attributes
that are not equals?
I tried to use "import java.util.Objects;" to use: "Objects.hash(referencia, monto, descripcion, NumeroParte);", so that may give me the results to print
First, your methods can be simplified by using the null-safe Objects helper methods added in Java 7:
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Objects.hashCode(this.NumeroParte);
result = prime * result + Objects.hashCode(this.descripcion);
result = prime * result + Double.hashCode(this.monto);
result = prime * result + this.referencia;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null || getClass() != obj.getClass())
return false;
COSTOS other = (COSTOS) obj;
return (Objects.equals(this.NumeroParte, other.NumeroParte)
&& Objects.equals(this.descripcion, other.descripcion)
&& Double.doubleToLongBits(this.monto) == Double.doubleToLongBits(other.monto)
&& this.referencia == other.referencia);
}
How could i implement a method that could print all the attributes that are not equals?
To print differences, do the same comparisons as the equals method:
public void printDifferences(COSTOS other) {
if (! Objects.equals(this.NumeroParte, other.NumeroParte))
System.out.println("Different NumeroParte: " + this.NumeroParte + " != " + other.NumeroParte);
if (! Objects.equals(this.descripcion, other.descripcion))
System.out.println("Different descripcion: " + this.descripcion + " != " + other.descripcion);
if (Double.doubleToLongBits(this.monto) != Double.doubleToLongBits(other.monto))
System.out.println("Different monto: " + this.monto + " != " + other.monto);
if (this.referencia != other.referencia)
System.out.println("Different referencia: " + this.referencia + " != " + other.referencia);
}
If I understand you requirement correctly, you want to print out the values of attributes which are not the same in 2 objects, then you can create a method as follows.
public void compareAttributes(COSTOS other) {
if (this.getMonto() != other.getMonto()) {
System.out.println("Not equal. This obj : " + this.getMonto()
+ " Other obj : " + other.getMonto());
}
// you can do the same for the remaining attributes.
}
EDIT:
As #Andreas, pointed out in the comments you should place this method in your COSTOS class itself so every object can be compared easily.

Connecting a wrapper class to another class

So I have this wrapper program that enables me to return two quantities from a method.
** Wrapper Class**
public class Words
{
private String leftWords;
private String rightWords;
public Words(String leftWords, String rightWords) {
this.leftWords = leftWords;
this.rightWords = rightWords;
}
public String getLeftWords() {
return leftWords;
}
public String getRightWords() {
return rightWords;
}
#Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result
+ ((leftWords == null) ? 0 : leftWords.hashCode());
result = prime * result
+ ((rightWords == null) ? 0 : rightWords.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;
Words other = (Words) obj;
if (leftWords == null)
{
if (other.leftWords != null)
return false;
}
else if (!leftWords.equals(other.leftWords))
return false;
if (rightWords == null)
{
if (other.rightWords != null)
return false;
}
else if (!rightWords.equals(other.rightWords))
return false;
return true;
}
}
The method I want to tie this with is :
private static Map <Set<String>,Set<Words>> getLeftRightWords(LinkedHashMap<Set<String>,Set<Integer>> nnpIndexTokens, NLChunk chunk) throws FileNotFoundException
{
// Map <Set<String>,Set<Integer>> nnpMap = new LinkedHashMap<Set<String>, Set<Integer>>();
Map <Set<String>,Set<Words>> contextMap = new LinkedHashMap<Set<String>, Set<Words>>();
Set<Words> leftRightWords = new HashSet<Words>();
//for(NLChunk chunk : sentence.getChunks()){
if(chunk.getStrPostags().contains("NNP")){
String leftWords = "";
String rightWords = "";
int chunkStartIndex = chunk.getStartIndex();
int chunkEndIndex = chunk.getEndIndex();
//nnpMap = getNNPs(chunk);
String previous = null;
int previousNnpEndIndex = 0;
int previousNnpStartIndex = 0;
for (Map.Entry<Set<String>, Set<Integer>> entry : nnpIndexTokens.entrySet()){
for (Iterator<String> i = entry.getKey().iterator(); i.hasNext();){
Set<Integer> entryIndex = null;
int nnpStartIndex = 0;
int nnpEndIndex = 0;
String currentElement = i.next();
//Deriving values for beginning and ending of chunk
//and beginning and ending of NNP
if (!(entry.getValue().isEmpty())){
if (currentElement.trim().split(" ").length > 1){
entryIndex = entry.getValue();
nnpStartIndex = entryIndex.iterator().next();
nnpEndIndex = getLastElement(entryIndex);
}
else {
entryIndex = entry.getValue();
nnpStartIndex = entryIndex.iterator().next();
nnpEndIndex = nnpStartIndex;
}
}
if(!(chunkStartIndex<=nnpStartIndex && chunkEndIndex>=nnpEndIndex)){
continue;
}
//Extracting LEFT WORDS of the NNP
//1)If another NNP is present in left words, left words of current NNP start from end index of previous NNP
if (previous != null && chunk.toString().substring(chunkStartIndex, nnpStartIndex).contains(previous)){
int leftWordsEndIndex = nnpStartIndex;
int leftWordsStartIndex = previousNnpEndIndex;
for (NLWord nlword : chunk.getTokens())
{
if(nlword.getIndex()>=leftWordsStartIndex
&& nlword.getIndex()<leftWordsEndIndex )
leftWords+=nlword.getToken() +" ";
}
System.out.println("LEFT WORDS:" + leftWords+ "OF:"+ currentElement);
}
//2) If no left words are present
if (chunkStartIndex == nnpStartIndex){
System.out.println("NO LEFT WORDS");
}
//3) Normal case where left words consist of all the words left of the NNP starting from the beginning of the chunk
else {
for (NLWord nlword : chunk.getTokens())
{
if(nlword.getIndex()>=chunkStartIndex
&& nlword.getIndex()<nnpStartIndex )
leftWords+=nlword.getToken() +" ";
}
System.out.println("LEFT WORDS:" + leftWords+ "OF:"+ currentElement);
}
//Extracting RIGHT WORDS of NNP
if (entry.getKey().iterator().hasNext()){// entry.getKey().iterator().hasNext()){
String nextElement = entry.getKey().iterator().next();
//1)If another NNP is present in right words, right words of current NNP start from end index of current NNP to beginning of next NNP
if (nextElement !=null && nextElement != currentElement && chunk.toString().substring(entry.getValue().iterator().next(), chunkEndIndex).contains(nextElement)){
int rightWordsStartIndex = entryIndex.iterator().next();
int rightWordsEndIndex = entry.getValue().iterator().next();
//String rightWord="";
for (NLWord nlword : chunk.getTokens())
{
if(nlword.getIndex()>=rightWordsStartIndex
&& nlword.getIndex()<rightWordsEndIndex )
rightWords+=nlword.getToken() +" ";
}
System.out.println("LEFT WORDS:" + leftWords+ "OF:"+ currentElement);
}
}
//2) If no right words exist
if(nnpEndIndex == chunkEndIndex){
System.out.println("NO RIGHT WORDS");
//continue;
}
//3) Normal case where right words consist of all the words right of the NNP starting from the end of the NNP till the end of the chunk
else {
for (NLWord nlword : chunk.getTokens())
{
if(nlword.getIndex()>=nnpEndIndex+1
&& nlword.getIndex()<=chunkEndIndex )
rightWords+=nlword.getToken() +" ";
}
System.out.println("RIGHT WORDS:" + rightWords+ "OF:"+ currentElement);
}
if (previous == null){
previous = currentElement;
previousNnpStartIndex = nnpStartIndex;
previousNnpEndIndex = nnpEndIndex;
}
Words contextWords = new Words(leftWords.toString(), rightWords.toString());
leftRightWords.add(contextWords);
}
contextMap.put(entry.getKey(), leftRightWords);
}//nnps set
}
System.out.println(contextMap);
return contextMap;
}
As you can see what I am trying to do in this method is taking a proper noun and extracting the left and right words of that proper noun.E.g for a chunk "fellow Rhode Island solution provider" my output is:
LEFT WORDS:fellow OF:Rhode Island
RIGHT WORDS:solution provider OF:Rhode Island
Now I want to put these in a map where Rhode Island is the key and the values for this are solution provider and fellow.
When I try to print this map the output get is:
{[Rhode Island ]=[com.gyan.siapp.nlp.test.Words#681330f0]}
How do i get the right output?
I don't know if it is the only issue but your class Words does not override
toString() method.
Not sure about your Java skill level. So sorry if im posting what you are familiar to.
System.out.println(...) calls toString() method to get message for the object.
By overriding default with your own implementation
#Override
public String toString(){
return "leftWords: "+leftWords+", rightWords: "+rightWords;
}
You change com.gyan.siapp.nlp.test.Words#681330f0 to your own output.

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

Getting unique enteries from the file

I am parsing a file with more than 4M lines in it. It is of the form a^b^c^d^...^....
Now i want all the unique points(only the 1st two entries should be unique) from the file. So what I do is,
String str;
Set<String> lines = new LinkedHashSet<String>();
Set<String> set = Collections.synchronizedSet(lines);
String str1[] = str.split("\\^");
set.add(str1[0]+"^"+str1[1]);
So this gives me the unique 1st and 2nd unique points from the file. However, I also want the 3rd point(timestamp) i.e str1[2] associated with the above points. The new file should be of the form.
str1[0]^str1[1]^str1[2]
How do I go about doing this?
There are a few solutions that come to mind.
Make a class for the 3 entries.
Override the equals method and only check on the first 2 entries there, so 2 objects are equal if the first 2 entries are equal. Now add all the items to the set.
So what you 'll get in your set is a list with unique first and second points and the first occaurance of your timestamp.
Another solution is to keep two lists, one with your 2 points + time stamp, one with only your 2 points.
The you can do set.contains(...) to check if you already saw the point and if you didn't add to the list with 2 points + timestamp.
Create a class containing the information you need which you will store in the set, but only care about the first two in equals/hashCode. Then you can do:
Set<Point> set = new HashSet<Point>();
String str1[] = str.split("\\^");
set.add(new Point(str1[0], str1[1], str1[2]));
Using:
public class Point {
String str1;
String str2;
String str3;
public Point(String str1, String str2, String str3) {
this.str1 = str1;
this.str2 = str2;
this.str3 = str3;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((str1 == null) ? 0 : str1.hashCode());
result = prime * result + ((str2 == null) ? 0 : str2.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;
Point other = (Point) obj;
if (str1 == null) {
if (other.str1 != null)
return false;
} else if (!str1.equals(other.str1))
return false;
if (str2 == null) {
if (other.str2 != null)
return false;
} else if (!str2.equals(other.str2))
return false;
return true;
}
}

Categories