How to fetch specific object from a set in Java - java

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)

Related

HashSet contains method with custom class [duplicate]

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

How to exclude some fields on TreeSet.contains but sort on all fields

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.

Edit element in arraylist, find index?

I'm about to create two methods for creating and changing customer profiles. Creating profile is no problem. Everything seems to go well there. But, when I shall then go in and change the profile, I get it not to work.
The indexOf() gives me -1, even though the value I search for available :S
Anyone have a good solution to this?
The problem is in the editProfile-method!
public class Profile{
String name;
long id;
int accNr = 1000;
double balance;
}
ArrayList<Profile> profileList = new ArrayList<Profile>();
public boolean newProfile(long id, String name, int amount){
Profile newProfile = new Profile();
Profile accNr = new Profile();
int ACC = accNr.accNr++;
newProfile.accNr = ACC;
newProfile.id = id;
newProfile.name = name;
newProfile.balance = amount;
profileList.add(newProfile);
return true;
}
public void editProfile(long id, String newName){
int ID = (int)id;
System.out.print(ID);
int index = profileList.indexOf(id);
System.out.print(index);
profileList.get(index);
}
The indexOf method will use the equals method to determine if your Profile exists in the list. You must override the equals method in Profile to return the proper result.
Second, it won't find your Profile, because you are passing a long to indexOf, and neither a long nor a Long will be found in the list. If you must retrieve the Profile by a long, then it makes more sense to have a Map<Long, Profile> instead of an ArrayList<Profile>. Then you can call get(id) to retrieve the Profile. Usually, you should override the hashCode method if you override equals, but because a Profile isn't being used as the key here, it's not necessary.
profileList contains Profile instances and you are trying to get the index of a long.
One solution would be overriding equals method in Profile class.
#Override
public boolean equals(Object obj) {
...
}
Another solution (not very recommended) would be looping over elements of profileList and manually checking for matches, like:
for (Profile element : profileList)
if (element.getID() == id)
...
Probably your Profileneeds to override equals and hashCode methods. Eclipse can generate then, Would be like taking your example:
public class Profile {
String name;
long id;
int accNr = 1000;
double balance;
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + accNr;
long temp;
temp = Double.doubleToLongBits(balance);
result = prime * result + (int) (temp ^ (temp >>> 32));
result = prime * result + (int) (id ^ (id >>> 32));
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;
Profile other = (Profile) obj;
if (accNr != other.accNr)
return false;
if (Double.doubleToLongBits(balance) != Double
.doubleToLongBits(other.balance))
return false;
if (id != other.id)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}

HashMap in java cannot hash MyObject

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.

Regarding Object Comparison

I am having a java class Rec. I have two instance of it Rec1 and Rec2. I want to check whether the values of Rec1 and Rec2 are equal. If i do Rec1.equals(Rec2) is it correct way of doing it?
class Rec {
private BigDecimal RecordId = null;
private BigDecimal recSubNum = null;
private BigDecimal FileId = null;
private String Category = null;
private BigDecimal status = null;
private BigDecimal errorCode = null;
}
You need to implement the equals() and hashCode() methods to implement object equality in Java:
class Rec {
private BigDecimal recordId = null;
private BigDecimal recSubNum = null;
private BigDecimal FileId = null;
private String category = null;
private BigDecimal status = null;
private BigDecimal errorCode = null;
#Override
public int hashCode() {
int ret = 41;
ret = hc(ret, recordId);
ret = hc(ret, recSubNum);
ret = hc(ret, fieldId);
ret = hc(ret, category);
ret = hc(ret, status);
ret = hc(ret, errorCode);
return ret;
}
#Override
public boolean equals(Object ob) {
if (ob == null) return false;
if (ob.getClass() != Rec.class) return false;
Rec r = (Rec)ob;
if (!eq(r.recordId, record)) return false;
if (!eq(r.recSubNum, recSubNum)) return false;
if (!eq(r.fileId, fileId)) return false;
if (!eq(r.category, category)) return false;
if (!eq(r.status, status)) return false;
if (!eq(r.errorCode, errorCode)) return false;
return true;
}
private static boolean eq(Object ob1, Object ob2) {
return ob1 == null ? ob2 == null : ob1.equals(ob2);
}
private static int hc(int hc, Object field) {
return field == null ? hc : 43 + hc * field.hashCode();
}
}
Note: the equals/hashCode contract for Java means that for any two objects a and b:
a.equals(b) == b.equals(a)
and if two objects are equal then a.hashCode() must equal b.hashCode().
Edit: there are two ways of checking if the types match. Either:
if (ob == null) return false;
if (ob.getClass() != Rec.class) return false;
or
if (!(ob instanceof Rec)) return false;
These two do different things and you should select the correct one depending on what you want to do. I generally prefer the first one unless you know you need the second. What's the difference?
class A {
public int i;
public boolean equals(Object ob) {
if (!(ob instanceof A)) return false;
return i == ((A)ob).i;
}
}
Looks reasonable right? What if the class gets extended:
class B extends A {
public int j;
public boolean equals(Object ob) {
if (!(ob instanceof B)) return false;
if (!super.equals(ob)) return false;
return j == ((B)ob).j;
}
}
Still looks reasonable? It's broken.
A a = new A();
a.i = 10;
B b = new B();
b.i = 10;
b.j = 20;
System.out.println(a.equals(b)); // true! Is this really what you want?
System.out.println(b.equals(a)); // false! Different to previous = problem.
That's why I favour getClass() over instanceof unless I really want subclass equality.
if Rec is a user defined class then you really should override the equals method otherwise it will just call the equals method in the Object class;
something like :
public boolean equals(Rec x){
//check here to see if the references are the same, if so return true
if(this == x) return true;
//if they aren't the same object then check all the fields for equality
if (category.equals(x.category) && etc etc) return true;
else return false;
}

Categories

Resources