I am writing a simple program as follow: Given two numbers M and N, p is from [M,N] and q is from [1,p-1], find all irreducible fractions of p/q.
My idea is brute force all possible value of p, q. And using HashSet to avoid duplicated fraction. However, somehow the contains function not working as expected.
My code
import java.util.HashSet;
import java.util.Set;
public class Fraction {
private int p;
private int q;
Fraction(int p, int q) {
this.p = p;
this.q = q;
}
public static int getGCD(int a, int b) {
if (b == 0)
return a;
else
return getGCD(b, a % b);
}
public static Fraction reduce(Fraction f) {
int c = getGCD(f.p, f.q);
return new Fraction(f.p / c, f.q / c);
}
public static HashSet<Fraction> getAll(int m, int n) {
HashSet<Fraction> res = new HashSet<Fraction>();
for (int p = m; p <= n; p++)
for (int q = 1; q < p; q++) {
Fraction f = new Fraction(p,q);
Fraction fr = reduce(f);
if (!res.contains(fr))
res.add(fr);
}
return res;
}
public static void print(Fraction f) {
System.out.println(f.p + "/" + f.q);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
HashSet<Fraction> res = getAll(2, 4);
for (Fraction f : res)
print(f);
}
}
Here is the output of program
4/3
3/1
4/1
2/1
3/2
2/1
you can see the fraction 2/1 is duplicated. Anyone can help me figure out why and how to fix it.
Many thanks.
Override the Object#equals and Object#hashCode methods in the Fraction class. These methods are used by HashSet to determine if two objects are the same. When you don't override them, the equals method tests equality of the objects' references rather that equality of their field values.
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + p;
result = prime * result + q;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Fraction other = (Fraction) obj;
if (p != other.p)
return false;
if (q != other.q)
return false;
return true;
}
You need to implement Fraction#equals() and Fraction#hashcode(), because that is used for determining weather the set contains certain value or not. Without it, object references are compared, which will not give you the desired result.
Your Fraction class does not override hashCode and equals. A HashMap contains tries to find a key with the same hashCode (and equals) as the one you provided. As you create a new instance of Fraction, it will never be the same as the one already in the HashMap. Here is how you would do hashCode and equals:
#Override
public int hashCode() {
return super.hashCode() + p * 24 + q * 24;
}
#Override
public boolean equals(Object other) {
if (!(other instanceof Fraction)) return false;
return ((Fraction) other).p == this.p && ((Fraction) other).q == this.q;
}
Related
I have looked at the other times this question has been asked on StackOverflow, but none of the other use cases seem to solve my problem. HashSet does not seem to realize that two objects are the same.
Basically, this is my class.
private static class Inconsistency
{
int a;
int b;
boolean isConsistency;
//Default constructor. To be used when we don't have an inconsistency
public Inconsistency()
{
this.a = -1;
this.b = -1;
this.isConsistency = false;
}
public Inconsistency(int a, int b, boolean isConsistency)
{
this.a = a;
this.b = b;
this.isConsistency = isConsistency;
}
#Override
public String toString()
{
if (this.isConsistency)
{
return "(" + this.a + ", " + this.b + ")";
}
else
{
return "No inconsistency";
}
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + a;
result = prime * result + b;
result = prime * result + (isConsistency ? 1231 : 1237);
return result;
}
#Override
public boolean equals(Object other)
{
if (this == other)
{
return true;
}
if (other == null)
{
return false;
}
if (this.getClass() != other.getClass())
{
return false;
}
Inconsistency otherInconsistency = (Inconsistency) other;
return ((this.a == otherInconsistency.a) && (this.b == otherInconsistency.b) && (this.isConsistency == otherInconsistency.isConsistency))
|| ((this.a == otherInconsistency.b) && (this.b == otherInconsistency.a) && (this.isConsistency == otherInconsistency.isConsistency));
}
}
I'm trying to store objects of my class inside a hashmap.
With the way I'm defining my equals method, an Inconsistency A (10, 20, true), should be equal to another Inconsistency B (20, 10, true) and when I test my equals method, this works correctly. However, when I try to insert both A and B into a HashSet, they both erroneously get added. I understand that I should manipulate my hashcode function but I'm not sure how to go about it.
Here's a driver showcasing the erroneous behaviour
Inconsistency A = new Inconsistency(10,20, true);
Inconsistency B = new Inconsistency(20,10, true);
System.out.println(A.equals(B)); // prints true as expected
HashSet<Inconsistency> test = new HashSet<>();
test.add(A);
test.add(B);
System.out.println(test); // prints [(10, 20), (20, 10)]. The two objects are equal but are both added to hashset
Just so the question is clear, How do I go about making sure that the two equal objects A and B both won't be added to my HashSet?
Your definition of equals means that two Inconsistency objects with their elements reversed are .equals, but your definition of hashCode does not return the same hash code if a and b are in a different order, which is a requirement if a HashSet or other hash-based collection is to work properly.
The simplest approach to fixing this is to do something commutative -- something that has the same result whichever order a and b are in. For example:
result = prime * result + a + b;
instead of
result = prime * result + a;
result = prime * result + b;
Have some problem with TreeSet or I just realize that it doesn't work as I expected.
I need to exclude some fields when I check if the value already exists, but on sort it should use all the fields.
It looks like TreeSet.contains() use compare or compareTo (comparator, comparable) and not equals().
Here is some example:
import java.util.Comparator;
import java.util.TreeSet;
public class sorter {
static class A {
String name;
int counter;
public A(String a, int counter) {
this.name = a;
this.counter = counter;
}
#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;
A other = (A)obj;
if (name == null) {
if (other.name != null) return false;
} else if (!name.equals(other.name)) return false;
return true;
}
}
public static class MyComparator implements Comparator<A> {
#Override
public int compare(A a, A b) {
int c = b.counter - a.counter;
if (c == 0) {
return a.name.compareTo(b.name);
};
return c;
}
}
public static void main(String[] args) {
TreeSet<A> set = new TreeSet<>(new MyComparator());
set.add(new A("a", 1));
if (set.contains(new A("a", 2))) {
System.out.println("'a' already exists, do count + count");
}
}
Feels like I breaking some law here, and should re-design it in some way?
Is it possible to achieve what I try to do with a TreeSet or should I go for a simple list?
In someway I have unique items and a list doesn't feel perfect either.
Any ideas?
You could change,
public int compare(A a, A b) {
int c = b.counter - a.counter;
if (c == 0) {
return a.name.compareTo(b.name);
};
return c;
}
to be
public int compare(A a, A b) {
if (Objects.equals(a, b))
return 0;
int c = b.counter - a.counter;
if (c == 0) {
return a.name.compareTo(b.name);
};
return c;
}
This way, if they are "equal" in your sense of equal, the TreeSet will exclude them. Otherwise you sort as you wish. As a note, the Objects.equals() will do the null checking for you.
It is using comparator to find equality.
Hash based collection only used equals and hashcode for equality.
But collection like tree using comparator for equality.
If two objects are equal then compare method should return true and vice versa.
set.contains(new A("a", 2)) its false because compare method wont return true`set.contains(new A("a", 1))` will return true because that method will return true.
I would like quickly to fetch from Java Set the object equal to existing one. Is there any faster way than iterating for all elements of the set?
Here is my code:
class A {
int a,b,c,d;
public A(int a, int b, int c, int d) {
this.a = a;
this.b = b;
this.c = c;
this.d = d;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + getOuterType().hashCode();
result = prime * result + a;
result = prime * result + b;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
A other = (A) obj;
if (!getOuterType().equals(other.getOuterType()))
return false;
if (a != other.a)
return false;
if (b != other.b)
return false;
return true;
}
private Main getOuterType() {
return Main.this;
}
}
and in the code:
void run() {
Set<A> a = new HashSet<>();
a.add(new A(1,2,3,4));
a.add(new A(2,3,4,5));
A b = new A(1,2,3,5);
//How to fetch from set a object equal to object b?
}
Is it possible to do it fast in Groovy?
There is not get method in java.util.Set interface. Hence, you can not fetch an entry :)
Maybe you are using the wrong data structure. May be what you need is a java.util.Map?
If you already have an object then there's no point in getting it from the Set. If you like to check if it exists in the set there is http://docs.oracle.com/javase/7/docs/api/java/util/Set.html#contains(java.lang.Object)
I want to store a set of Edges:
class Edge {
int u;
int v;
char symbol;
}
The problem is that it's possible for two Edge objects to have the same u, v and symbol, but they can both be stored in a HashSet because they're not the same object even though I want them to be considered the same object. How can I store only one object that has a unique (u, v, symbol) in a Set?
You need to override the following two methods equals and hashcode.
public boolean equals(Object obj) {
if (obj == null) return false;
if (!(obj instanceof Edge)) return false;
// return true if they are the same, otherwise false
}
public int hashCode() {
// return an int that represents similarity
// Example: name.hashCode(), if they are the same with the same name
}
Depends on what kind of set you want to use; The below applies for HashSet for instance, but not for any subclass of SortedSet
By overriding equals() and hashCode():
class Edge {
int u;
int v;
char symbol;
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + symbol;
result = prime * result + u;
result = prime * result + v;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Edge other = (Edge) obj;
return symbol == other.symbol && u == other.u && v == other.v;
}
}
You have to override equals(). Like this:
public boolean equals(Object obj) {
//do the comparison here; remember to cast obj to Edge
}
I have defined a simple private class named SetOb which contains an int and a Set data structure. I have a HashMap in the 'main' method with SetOb as Key and Integer as value. Now as you can see in the main method, when I feed the HashMap with a SetOb instance and then look for an instance with exactly the same value, it returns 'null'. This has happened with me quite a few times before when I use my own defined data structures like SetOb as Key in HashMap. Can someone please point me what am I missing ?
Please note that in the constructor of SetOb class, I copy the Set passed as argument.
public class Solution {
public static Solution sample = new Solution();
private class SetOb {
public int last;
public Set<Integer> st;
public SetOb(int l , Set<Integer> si ){
last = l;
st = new HashSet<Integer>(si);
}
}
public static void main(String[] args) {
Map<SetOb, Integer> m = new HashMap< SetOb, Integer>();
Set<Integer> a = new HashSet<Integer>();
for(int i =0; i<10; i++){
a.add(i);
}
SetOb x = sample.new SetOb(100, a);
SetOb y = sample.new SetOb(100, a);
m.put(x,500);
Integer val = m.get(y);
if(val!= null) System.out.println("Success: " + val);
else System.out.println("Failure");
}
}
Your x and y are not the same object instances hence contains is not able to match y against x, which ends up not finding the matching key/value in the Map.
If you want the match to succeed, please implement(override) hasCode & equals method in SetOb which will compare the field values.
Sample methods(Eclipse generated) as below:
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + last;
result = prime * result + ((st == null) ? 0 : st.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;
SetOb other = (SetOb) obj;
if (last != other.last)
return false;
if (st == null) {
if (other.st != null)
return false;
} else if (!st.equals(other.st))
return false;
return true;
}
The default implementation of hashCode uses object identity to determine the hash code. You will need to implement hashCode (and equals) in your private class if you want value identity. For instance:
private class SetOb {
public int last;
public Set<Integer> st;
public SetOb(int l , Set<Integer> si ){
last = l;
st = new HashSet<Integer>(si);
}
#Override
public boolean equals(Object other) {
if (other.class == SetOb.class) {
SetOb otherSetOb = (SetOb) other;
return otherSetOb.last == last && otherSetOb.st.equals(st);
}
return false;
}
#Override
public int hashCode() {
return 37 * last + st.hashCode();
}
}
SetOb needs to override the hashCode() and thus the equals() methods.
Hash-based collections use these methods to store (hashCode()) and retrieve (hashCode()) and equals()) your objects.