HashSet inserts 2 elements which are equal - java

I was recently working on a basic task which involved a set and I stumbled upon a curious problem. I have the following class:
public static class Quadruple {
int a;
int b;
int c;
int d;
Map<Integer, Integer> histogram;
public Quadruple(int a, int b, int c, int d) {
this.a = a;
this.b = b;
this.c = c;
this.d = d;
this.histogram = new HashMap<>();
histogram.put(a, histogram.get(a) == null ? 1 : histogram.get(a) + 1);
histogram.put(b, histogram.get(b) == null ? 1 : histogram.get(b) + 1);
histogram.put(c, histogram.get(c) == null ? 1 : histogram.get(c) + 1);
histogram.put(d, histogram.get(d) == null ? 1 : histogram.get(d) + 1);
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Quadruple)) {
return false;
}
Quadruple q = (Quadruple) obj;
return q.histogram.equals(this.histogram);
}
#Override
public int hashCode() {
return Objects.hash(a, b, c, d);
}
When I initialize 2 objects of this type like so:
Quadruple q1 = new Quadruple(1, 1, 1, 2);
Quadruple q2 = new Quadruple(1, 1, 2, 1);
q1.equals(q2) returns true but both objects can be added separately to a HashSet.
Now I understand from the contract of HashSet, that if the object you are trying to add equals() an already present object, it should be considered present and nothing should be done.
I've managed to circumvent this issue by using LinkedList and checking if the list contains() the object before adding it, which seems to work accordingly.
My question is, is this behavior normal, as I checked the underlying implementation and saw that the HashMap which is used in HashSet actually checks the values with equals(). Is there something I might be missing?

Your equals method compares histogram, but your hashCode computes the hash from 4 other fields instead. Your implementation of hashCode method violates the contract between equals and hashCode, which says that if two object are equal, they have to have the same hash.
If you look at the implementation of Objects.hash you will get to this code:
public static int hashCode(Object a[]) {
if (a == null)
return 0;
int result = 1;
for (Object element : a)
result = 31 * result + (element == null ? 0 : element.hashCode());
return result;
}
And as you can see in the loop, the order of arguments passed to Object.hash matters.
As for the solution, I can't really see a reason to have fields other than histogram at all. Either way, given the implementation of your equals method, your hashCode method should look like this:
#Override
public int hashCode() {
return histogram.hashCode();
}

Related

is there any way to delete an object while creating it?

I'm practising towards finals and I have faced this question -
Given the following code, is there any way that the there is an implementation of class A such that at the end it will print 5 in one run of the program, then in other run of the program 4, then another run 3...till 0.
Can assume that it's deterministic so functions will generate always the same results.
Can't delete any code in class A and not in the main, and able only to edit A class.
public class A {
int i, j;
public A(int i, int j) {
this.i = i;
this.j = j;
}
public static void main(String[] args) {
Set<A> s = new LinkedHashSet<>();
s.add(new A(3,1));
s.add(new A(1,3));
s.add(new A(3,1));
s.add(new A(3,1));
s.add(new A(2,1));
System.out.println(s.size());
}
}
I was thinking to add kind of static HASHMAP and every time I create an object I will add it to there and I will check if one key already exists then I would like to "not create" the object if one with same values already exists... but not able to implement it.
You're going to want to implement equals and hashcode into class A. You should implement them in such a way that it will cause collisions when adding items into Set s.
By default, it should print out the number 5.
But, if we make the following edit:
public class A {
int i, j;
public A(int i, int j) {
this.i = i;
this.j = j;
}
#Override
public boolean equals(Object obj) {
// First we check if the object is null
// Then we check if it's the same class as this one
if(obj == null || obj.getClass()!= this.getClass()) {
return false;
}
A objectA = (A) obj;
if(this.i == objectA.i) {
return true;
} else {
return false;
}
}
#Override
public int hashCode()
{
return this.i;
}
This particular implementation will result in printing out '3'. This is because we set it so that the hashcode is equal to i. Therefore when we add two instances of class A to the set, they will collide.
In our case, when instances of class A are added, the values for i are 3, 1, 3, 3, 2, there are 3 unique values of i (3, 1, 2), so therefore it will print 3.
From here you can come up with different implementations to get different values.

Whats wrong with this boolean method?

Hi I have this method which I created. Its job is to receive an Integer A, which can either be 10 or 30. It is meant to return TRUE if the value is ten, and false otherwise.
public static boolean checkStatus(int a){
if(a.equals(10)){
return true;
}
return false;
}
For some reason I am getting a compilation error in the if(a.equals(10)) condition, which says INT CANNOT BE DEREFERNCED. If I'm not mistaken, isn't the .equals() method the way to go in this circumstance?
Thanks for your help!
Primitives in Java (int, long, float, etc..) don't have member methods, so the call
if (a.equals(10))
will not compile, as you're trying to de-reference a primitive. Instead, you want to use the == operator to compare primitive values:
if (a == 10)
and reserve the use of the equals() method for non-primitive Objects
You can use equals for objects but an int is a primitive type (a), rather than an object.
Hence you need something like:
public static boolean checkStatus (int a) {
if (a == 10)
return true;
return false;
}
or the shorter and more sensible (in this case):
public static boolean checkStatus (int a) {
return (a == 10);
}
(a) The purists will argue this is proof that Java is not really an object-oriented language, but that's because they're raving loonies :-)
You can use
public static boolean checkStatus(int a){
if(a==10){
return true;
}
return false;
}
or
public static boolean checkStatus(Integer a){
if(a.equals(new Integer(10))){
return true;
}
return false;
}
equals() method belongs to Object class of Java and it has to override each and every Object classes like String, Integer and MyObject(implemented class). But int is not a Java Object and there is no equals() method there.
you can just use == with int values and you can simplify your code as bellow.
public static boolean checkStatus(int a){
return a==10;
}
equals is used for non-primitives basically for Objects.
== is used for primitives.
So, you can use it
public static boolean checkStatus (int a) {
if (a == 10)
return true;
return false;
}
Example 1:
For object, if equals method are overridden, then "equals" method will return true.
public class Employee {
int id;
#Override
public boolean equals(Object obj) {
Employee e = (Employee) obj;
return id == e.id;
}
Employee(int id) {
this.id = id;
}
public static void main(String[] args) {
Employee e1 = new Employee(5);
Employee e2 = new Employee(5);
System.out.println("e1.equals(e2) is: " + e1.equals(e2));
System.out.println("(e1 == e2) is: " + (e1 == e2));
}
}
Output:
e1.equals(e2) is: true
(e1 == e2) is: false
Example 2:
For object, if equals method are not overridden, then "equals" method works as "=="
public class Employee {
int id;
Employee(int id) {
this.id = id;
}
public static void main(String[] args) {
Employee e1 = new Employee(5);
Employee e2 = new Employee(5);
System.out.println("e1.equals(e2) is: " + e1.equals(e2));
System.out.println("(e1 == e2) is: " + (e1 == e2));
}
}
Output:
e1.equals(e2) is: false
(e1 == e2) is: false
Here "equals" method works as "==". So, don't forget to override the equals method for object.
int is a primitive in Java and primitives does not have behaviours a.k.a methods.
hence you cannot call .equals on int. So the options here are to use a ==
public static boolean checkStatus(Integer a){
return (a==10);
}
or convert the int to Integer which is a wrapper class
public static boolean checkStatus(Integer a){
return a.equals(10);
}
You can do something like this with Integer Class
Integer x = 5;
Integer y = 10;
Integer z =5;
Short a = 5;
System.out.println(x.equals(y));
System.out.println(x.equals(z));
System.out.println(x.equals(a));
Output:
false
true
false
You can of course wrap the integer up as :
Integer i = new Integer(a);
Then the equals function can be used with 'i', the new Integer object.

Defining a comparator for a quadratic function object

This is my assignment,
a) Write a quadraticFunction that represents a quadratic ax^2 + bx + c with int coeffients a, b, c. Provide a constructor with 3 int parameters for a, b, c. Provide a method double valueAt(double x) returns the value of this quadratic function at x. Also provide a toString method.
b) override the equals method quadraticmethod class. two quadraticfunction should be considered equal if their respective coeffiecients are equal
c) Make the function objects comparable. The compareTo should first compare 1 if equal compare b if equal compare c
d) Define a comparator class for comparing two QuadraticFunction objects. Provide two constructors: a no-argss constructor and a constructor that takes 1 double parameter. When a comparator is created by the no-args constructor, it should compare two quadraticFunction based on their values at x = 0; when a comparator is created by the constructor with a parameter x, it should compare quadraticFunction based on their values at x
Here's my code
I need help with part D, I don't know how to do some of it
public class Ex4
{
int a;
int b;
int c;
public Ex4(int x, int y, int z)
{
a = x; b=y; c=z;
}
public String toString()
{
String X="";
X= X+a+"x^2"+b+"x"+ "+" + c;
return X;
}
public double valueAt(double x)
{
return (a*x*x+b*x+c);
}
//////// Part B
public boolean equals( Ex4 qf )
{
return(this.a==qf.a && this.b==qf.b && this.c==qf.c);
}
/////Part c
// public int compareTo(Ex4 other)
// {
// if (a.equals(other.a))
// {
// if (b.equals(other.b))
// return c.compareTo(other.c);
// return b.comapreTo(other.b);
// }
// return a.compareTo(other.a);
// }
public int compareTo(Ex4 other)
{
if (a > other.a)
return 1;
else if (a < other.a)
return -1;
else if (b > other.b)
return 1;
else if (b < other.b)
return -1;
else if (c > other.c)
return 1;
else if (c < other.c)
return -1;
else
return 0;
}
////Part d
public static void main(String[] args)
{
System.out.println(new Ex3(1, -5, 6));
}
}
Also in the uncomment the area of code under part c, it says int cannot be dereferenced on line 29, 31, 32,33, and 35
Thanks for the help
You can't call methods on primitives, plain and simple.
A better option is to use Integer's static method, Integer.compare(int a, int b) to compare two ints.
First, writing a custom Comparator isn't too terribly difficult; you need to understand the basic structure of one.
Here's the idea: it reads kind of like you're writing a Comparable entity.
class CustomComparator implements Comparator<Ex4> {
#Override
public int compare(Ex4 left, Ex4 right) {
// Compare the entities as specified by the assignment
}
}
Then, you need to accept that as a constructor argument. That, I leave as an exercise to the reader.
Now, to the syntax issue: you're treating primitive int as an Integer, which does have an equals method on it. Primitives aren't objects, hence they can't be dereferenced. You'll want to use the normal equivalence operators (==, >, <) in this situation. You have this already solved in your second-defined compareTo method.
EDIT: After re-reading your requirements, I'm starting to think that your primitive fields are not the right way to go. You should:
Change your fields from int to Integer
Implement Comparable<Ex4> on your entity class
Rely on the default behavior of compareTo() for Integer; that is, your commented code should "just work" (save for the misspell when comparing against C)
Move the secondary compareTo to its own Comparator entity, as described above.
Try this
import java.util.Comparator;
public class Ex4Comparator implements Comparator<Ex4> {
private double x = 0.0;
public Ex4Comparator() {
}
public Ex4Comparator(double x) {
this.x = x;
}
#Override
public int compare(Ex4 o1, Ex4 o2) {
return Double.compare(o1.valueAt(x), o2.valueAt(x));
}
}
Also your equals method doesn't override Object's equals method. You may want to change it to something like
#Override
public boolean equals(Object o) {
if (o instanceof Ex4) {
Ex4 other = (Ex4)o;
return (a == other.a && b == other.b && c == other.c);
}
return false;
}

How to make the java HashSet / HashMap work with any Object?

Is it possible to make HashSet work with any Object ?? I tried to make the Object implement
Comparable but it didn't help
import java.util.HashSet;
public class TestHashSet {
public static void main(String[] args) {
class Triple {
int a, b, c;
Triple(int aa, int bb, int cc) {
a = aa;
b = bb;
c = cc;
}
}
HashSet<Triple> H = new HashSet<Triple>();
H.add(new Triple(1, 2, 3));
System.out.println(H.contains(new Triple(1, 2, 3)));//Output is false
}
}
you need to implement equals(Object) and hashCode()
ensure that the hashcodes are equal when the objects are equal
in your example:
class Triple {
int a, b, c;
Triple(int aa, int bb, int cc) {
a = aa;
b = bb;
c = cc;
}
public boolean equals(Object arg){
if(this==arg)return true;
if(arg==null)return false;
if(arg instanceof Triple){
Triple other = (Triple)arg;
return this.a==other.a && this.b==other.b && this.c==other.c;
}
return false;
}
public int hashCode(){
int res=5;
res = res*17 + a;
res = res*17 + b;
res = res*17 + c;
//any other combination is valid as long as it includes only constants, a, b and c
return res;
}
}
For it to work properly you'll need to implement equals() and hashcode() and you'll also need to make sure they're implemented properly, following the contract set out in the Javadoc (it's perfectly possible to implement them not following this contract but you'll get bizarre results with potentially hard to track down bugs!)
See here for a description.
It already does work with any object. I suggest you need to read the Javadoc instead of guessing about the requirements.

== vs equals method for Doubles [duplicate]

This question already has answers here:
Why can't we use '==' to compare two float or double numbers [duplicate]
(3 answers)
Closed 6 years ago.
I have this class
public class Point {
private Double[] coordinates;
private int dimension;
public Point(Double[] coordinates) {
dimension = coordinates.length;
this.coordinates = new Double[dimension];
for(int i = 0; i < dimension; i++)
this.coordinates[i] = coordinates[i];
}
public Double getCoord(int n) {
if(n < 0 || n > dimension -1 ){
throw new RuntimeException("error de coordenadas");
}
return coordinates[n];
}
public int getDim() {
return dimension;
}
public boolean equals(Object p1){
if( (p1 instanceof Point) ){
Point p = (Point) p1;
int n = p.getDim();
if(getDim() == n)
{
for(; n > 0; n--)
{
if( Double.valueOf(this.getCoord(n-1)) != Double.valueOf(p.getCoord(n-1)) ) // <------- BAD LINE!
{
System.out.println("Checking coord " + (n-1));
System.out.println("Coord " + (n-1) + " p = " + Double.valueOf(this.getCoord(n-1)));
System.out.println("Coord " + (n-1) + " p2 = " + Double.valueOf(p.getCoord(n-1)));
return false;
}
}
}
return true;
}
return false;
}
}
And this main
public class FigureTest {
public static void main(String[] args){
Double[] coord1 = {2.0,3.3};
Double[] coord2 = {2.0,3.3};
Point p = new Point(coord1);
Point q = new Point(coord2);
System.out.println(p.equals(q));
}
}
I can't understand why this p.equals(q) returns false! It goes inside the if( Double.valueOf(... but then prints that both coordinates are equal. It's the same if I remove the Double.valueOf. The only way it worked was when I put ! if(this.getCoord(n-1).equal(p.getCoord(n-1)), but I don't understand why the others don't work.
Double.valueOf returns a Double object, not a primitive double.
You perform a reference check (!=). So even if Double.valueOf(getCoords(n-1)) returned the same numeric value for both calls, different objects would be wrapping the numbers, so the != check would be true, causing your equals to return false.
Here's a quick example:
public static void main(String[] args){
System.out.println(Double.valueOf(5) == Double.valueOf(5));
}
Notice how it returns false. That's because == is a reference check, and a different object is being returned each time you call Double.valueOf. So when you do
Double.valueOf(...) != Double.valueOf(...)
That check will return true, since the valueOf calls didn't return the same object. This is why the check in your code returns true, resulting in equals returning false.
To fix this, you could...
Change your != check into a .equals check, which will compare the numeric values rather than the references.
Double.valueOf(...).equals(Double.valueOf(...));
This returns true if both share the same numeric value.
Or you could use doubleValue() when you call getCoord:
getCoord(n-1).doubleValue() != other.getCoord(n-1).doubleValue()
This will avoid the excess creation of Double objects.
In order to this to work;:
p.equals(q)
you need to keep the contract between Hashcode and equals and override properly both of them: equals AND hashcode in the class Point, and when I write properly I mean specifically this:
Please refer to this question if you dont know why or that you dont need it
Double.valueOf(this.getCoord(n-1)) != Double.valueOf(p.getCoord(n-1))
if the members of the class Point are doubles, then you are right when you compare those doubles as criteria to decide if p1.equals(p2)
but according to the documentation of the class Double, the static method Double.compare(this.getCoord(n-1)),p.getCoord(n-1) must be use in order to compare 2 doubles content.
hence I recommend to do in the equals method some similar to this
if( Double.compare(this.getCoord(n-1)),p.getCoord(n-1)!=0) )

Categories

Resources