How to change the value of a key in hashmap - java

I have a project where I need to convert the value of x into 1+5 and calculate it to 6.
I have no problem if x is the only value that needs to be converted, but if I have (5*x) it becomes an issue. Rather than doing 5*(1+5) and calculate it to 30, it simply tries to compute 5*x and this results to an exception that says it cannot compute because a variable is present.
The ExpFoo class is an interface and it's the superclass of TimesExpFoo, PlusFoo, IntFoo and VarFoo. Replacement class is completely separated.
TimesExpFoo multiplies the number and PlusFoo adds the numbers.
Here's the Main class. This gets the varfoo and numbers. The Replacement class puts the varfoo and numbers in a hashmap that's used by the Replacement class. The varfoo is the key and the numbers are the values.
ExpFoo x = new VarFoo("x");
ExpFoo e1 = new IntFoo(1);
ExpFoo e2 = new IntFoo(2);
ExpFoo e5 = new IntFoo(5);
ExpFoo times = new TimesExpFoo(e5, x);
Replacement s = new Replacement();
s.put(new VarFoo("x"), new PlusExpFoo(e1, e5));
times.computeValue(s);
System.out.println(times.computeValue(s));
It will then go to ExpFoo class using computeValue method, the subst contains [x:=1+5], it will first check the applyReplacement method:
default int computeValue(Replacement subst) {
ExpFoo specialised = applyReplacement(subst);
return specialised.computeValue();
}
It will then go to TimesExpFoo class using applyReplacement method, it will return [x:=1+5]:
#Override
public ExpFoo applyReplacement(Replacement s) {
return this;
}
It will go to back ExpFoo class, this time specialised has (5*x) and subst has [x:=1+5], it will unfortunately return specialised value which is (5*x):
default int computeValue(Replacement subst) {
ExpFoo specialised = applyReplacement(subst);
return specialised.computeValue();
}
It will then go to TimesExpFoo's computeValue method, the getLeft method contains 5 and getRight method contains x:
#Override
public int computeValue() {
return getLeft().computeValue() * getRight().computeValue();
}
Which will finally go to the VarFoo class and use the computeValue method which will throw an error that it cannot compute because of a variable present.
I'm aware that TimesExpFoo's applyReplacement method returns the value of subst itself and I could do more with it but I'm not sure how it works. I've tried using return s.get((VarFoo) getRight()) but it will just give me a casting error TimesExpFoo cannot be cast to class VarFoo.
My VarFoo class overrides the equals and hashcodes methods. If the varfoo, x, has the same hashcode and it should overwrite 5*x with 5*(1+5). It has no problem doing it on its own.
I'm puzzled by the fact that it wouldn't overwrite the x variable. Does it has something to do with the hashmap?
My applyReplacement method is just a signature in the Expression class, so I doubt that's the issue.
Here's the Replacement class which uses hashmap:
public class Replacement {
private Map<VarFoo, ExpFoo> replacementMap;
public Replacement() {
replacementMap = new HashMap<>();
}
public ExpFoo put(VarFoo var, ExpFoo exp) {
if(replacementMap.containsKey(null) || replacementMap.containsValue(null)){
throw new NullPointerException();
}
return replacementMap.put(var, exp);
}
public boolean forget(VarFoo var) {
if(replacementMap.containsKey(null)) {
throw new NullPointerException();
}
else {
if(!replacementMap.containsKey(var))
return true;
}
return false;
}
public ExpFoo get(VarFoo var) {
if(replacementMap.containsKey(null)){
throw new NullPointerException();
}
return replacementMap.get(var);
}
public boolean hasMappingFor(VarFoo var) {
if(replacementMap.containsKey(var)){
return true;
}
else if(replacementMap.containsKey(null)){
throw new NullPointerException();
}
return false;
}
}
My VarFoo's equals and hashcode methods, it uses the instance variable name which is a String:
#Override
public boolean equals(Object o) {
if (o == null) return false;
if (!(o instanceof VarFoo))
return false;
if (o == this)
return true;
return name.equals(((VarFoo) o).name);
}
#Override
public int hashCode() {
int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
The TimesExpFoo class is a subclass of BinaryExpFoo which is an abstract class and it's the subclass of ExpFoo. The BinaryExpFoo is the one that gives the left, right and operatorSymbol instance variables.
public class TimesExpFoo extends BinaryExpFoo {
public TimesExpFoo(ExpFoo left, ExpFoo right) {
super(left, right, "*");
}
#Override
public int computeValue() {
return getLeft().computeValue() * getRight().computeValue();
}
#Override
public ExpFoo applyReplacement(Replacement s) {
return this;
}
#Override
public boolean equals(Object o) {
if (!(o instanceof TimesExpFoo)) {
return false;
}
return super.equals(o);
}
#Override
public int hashCode() {
return super.hashCode();
}

The HashMap uses hashCode and equals to check if the key already present in the map. If the key already exists the old value is replaced with a new one. The key itself remains unmodified.
If you want to use instances of the VarFoo class as HashMap keys, you have to override the hashCode() method so that it adheres to the contract: Equal objects return the same hashCode.
One common way is to let our IDE generate the equals() and hashCode() method for your VarFoo class

The goal of your applyReplacement() method is to replace all the variables by their real values/expressions. The only expression which can do that is obviously the VarFoo class. Its method might look like this:
#Override
public ExpFoo applyReplacement(Replacement s) {
ExpFoo exp = s.get(this);
exp = exp.applyReplacement(s); // replace any contained variables as well
return exp;
}
Similar to the computeValue() method, the applyReplacement() method has to be implemented recursively for classes which contain other ExpFoo objects. These "inner" expressions has to be "transformed" as well, where the variables are being replaced. As an example, for the TimesExpFoo class the method might look like this:
#Override
public ExpFoo applyReplacement(Replacement s) {
return new TimesExpFoo(
this.left.applyReplacement(s),
this.right.applyReplacement(s)
);
}
This way the TimesExpFoo object gets translated to a similar TimesExpFoo object without any variables anymore. Then you can use your computeValue() method since everything has been replaced.
Your actual implementation has to check for chained variable replacements. Imagine you have the expressions:
x = 5
y = 4+x
z = 3+y
You might need some kind of loops or recursive calls (like shown above) so the expression z will finally be transformed into 3+4+5 and not just stop at 3+y.

Related

How to correctly implement equals(), hashCode() if the values are within a range of each other?

The criteria is that equals() method where the objects are considered equal if the value of the double variable is within +/- 10 of the other object's value of the double variable.
I'm not sure how to correctly implement hashCode() so that the hashCode would be equal if it satisfies the conditions of the equals() method.
I would really appreciate your input! Thanks!
public class Test
{
private double value;
private boolean isEqualValues (final double valueOne, final double valueTwo)
{
if(valueOne == valueTwo)
{
return true;
}
else if((valueOne - valueTwo <= 10) &&
(valueOne - valueTwo >= -10))
{
return true;
}
else
{
return false;
}
#Override
public boolean equals(final Object o)
{
if (this == o)
{
return true;
}
if (o == null || getClass() != o.getClass())
{
return false;
}
Test test = (Test) o;
if(isEqualValues(test.value, value))
{
return true;
}
else
{
return false;
}
}
//How to implement hashCode()
#Override
public int hashCode()
{
//unsure how to correctly implement hashCode() so that the hashCode would be equal if it
//satisfies the conditions of the equals() method above
}
}
There's no way to consistently implement this, since equals() demands transitivity:
It is transitive: for any non-null reference values x, y, and z, if x.equals(y) returns true and y.equals(z) returns true, then x.equals(z) should return true.
new Test(1), new Test(9) and new Test(14) would fail that test (assuming a trivial one-argument constructor that assigns its argument to value).
One way to work around that is to not check for the absolute distance, but "categorize" your objects using some formula, for example take the floor of value / 10 and compare that.
This way some "close" values like new Test(9) and new Test(11) would compare as not-equal, but other than that you'd get a similar result to what you described.
private long getEquivalenceGroup() {
return Math.floorDiv((long) value, 10);
}
#Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Test test = (Test) o;
return test.getEquivalenceGroup() == this.getEquivalenceGroup();
}
#Override
public int hashCode()
{
return Long.hashCode(getEquivalenceGroup());
}
As long as getEquivalenceGroup() is implemented in a stable manner this will produce "groups" of slightly different objects that still compare as equal and has a valid hashCode() implementation.
Note: if you want a comparison as described in the question but you don't necessarily need it to be returned by equals() then adding a boolean isClose(Test other) is perfectly fine. The only problem is you are trying to implement the equals method specifically with that semantic.
You can't and you shouldn't.
You should implement a comparator and do such operations using that.

Revert Hashmap to previous value

I have a class called Varfoo that stores variables. I have another class called Replacement that uses a hashmap to replace the x into 2. With the forget method, it's meant to forget replacing x with 2.
Varfoo x = new VarFoo("x");
Replacement s = new Replacement();
s.put(new VarFoo("x"), new IntFoo(2));
x.applyReplacement(s);
s.forget(x);
Here's the forget method:
public boolean forget(VarFoo var) {
if (var == null) {
throw new NullPointerException();
} else {
if (replacementMap.containsKey(var)) {
replacementMap.remove(var);
return true;
} else {
return false;
}
}
}
It will result to null because I've removed the key itself, not what I intended. How do I revert it back to how it was?
Equals and hashcodes of Varfoo:
#Override
public boolean equals(Object o) {
if (o == null) return false;
if (!(o instanceof VarFoo))
return false;
if (o == this)
return true;
return name.equals(((VarFoo) o).name);
}
#Override
public int hashCode() {
int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
You can make a new implementation of Map, that contains two (e.g.) HashMaps. In normal mode it forwards every operation to map1. This is the original map. map2 is null.
When you make a savepoint, you assign an empty map to map2. get operations now go first to map2 and then, if not found, to map1. put operations go only to map2. When you call forget, you assign again null to map2.
Of course, you must implement all the other methods of the Map interface. But this should be a simple task. Take care of removes, if needed (maybe you will need a Set of removed keys.
Hint: You can use java.util.AbstractMap as a base for your implementation.

Keys match, but get/containsKey don't find it

I am trying retrieve a value from a hashmap. The keys are TransitionKey objects which have implemented equals and hashcode. When I use equals(...) to compare the key I want to look up and the current key in the hashmap, it returns true, but get returns null and containsKey returns false. I have not modified the key in any way since adding it to the hashmap. Can anyone help?
TransitionKey current = new TransitionKey(this.currentState, inputSymbol);
for(TransitionKey tk: transitions.keySet()) {
System.out.println(tk.equals(current)); // True (only one key in table)
System.out.println(transitions.containsKey(current)); // false
String value = transitions.get(tk).toString(); // null
}
In the TransitionKey class:
/**
* #override
*/
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof TransitionKey)) return false;
TransitionKey transitionKey = (TransitionKey) o;
return (state.equals(transitionKey.state)) && (symbol==transitionKey.symbol);
}
/**
* #override
*/
public int hashcode() {
int result = (int)symbol;
result = result*31 + state.hashCode();
return result;
}
You haven't overriden hashCode, you have created a new hashcode method (note the c vs. C).
Change your code to
#Override
public int hashCode() {
int result = (int)symbol;
result = result*31 + state.hashCode();
return result;
}
And it should work as expected.
Note that if you hadn't commented out the #Override annotation, you would have received a useful compiler error.

Is it possible to enter duplicate value in HashSet?

I am trying to add duplicate values in HashSet by modifying its hashCode() and equals() method()?
I tried below code
public class dupSet {
static Set set= new HashSet();
#Override
public int hashCode() {
return (int) (100*Math.random());
}
#Override
public boolean equals(Object obj) {
return false;
}
public static void main(String[] args) throws ParseException {
set.add("a");
set.add("b");
set.add("a");
System.out.println(set);
}
}
As per my understanding if for two duplicate of "a" HashSet will first get hashCode() to get proper bucket and then check value of equals() if equals returns true then it will not add but if it return false then it will add.
So for adding duplicate value to my Set I override equals() which always return false but still set is not allowing duplicate values?
You hashCode method returns always zero. Have a look at the range of Math.random().
Second, you do not override equals and hashCode of the elements you add. You actually add a String. To make things work, you must implement a class and add instances of that class to you HashSet. The implemented class needs to override the equals and hashSet method, not the main class.
Third, as stated in the comments, you shouldn't do what you are doing. What you realy want is a ArrayList. By implementing the equals and hashCode methods this way, a fundamental contract is broken.
I read source code and from that I am able to understand how its work
so need some help
First of all
Set is a collection of well defined and distinct objects
So there is no question of adding duplicates values. But if you are interested in understanding how java achieve/implement this constraint , then you can start digging in the source code.
A HashSet is backed by HashMap which mean that it delegates it operations like add, remove, etc. to HashMap .Now When you call set.add("a"); then
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
is called, which in turn calls HashMap#put
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
The put method first calcuates the hash code of the object using
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
Once the hashCode is calculated the it calls
final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict)
inside this method , it put the value because this condition
if ((p = tab[i = (n - 1) & hash]) == null)
is true and it then increments the modCount(which stores the number of times the HashMap has been structurally modified), checks if we need to resize the map and then call afterNodeInsertion and returns null
Now when you call set.add("b"); then the same logic runs again but this time the condition inside final V putVal method
if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))
holds true and due to this , the code
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
detects the existing mapping and thus return the oldValue . Hence preventing adding duplicate value.
You want the objects in the Set to include duplicates I assume (if just for curiosity keep reading, otherwise just choose other collection. this might help)
Let me make some corrections:
public class DupSet<E extends Comparable<E>>{
private Set<E> mySet = new HashSet<>();
//Implement add, remove and size
}
public class MyNeverEqualClass implements Comparable<MyNeverEqualClass>{
private static int stupidHash = 0;
private int num;
public MyNeverEqualClass(int num){
this.num = num;
}
#Override
public int compareTo(MyNeverEqualClass other){
double rnd = Math.random()*3 + 1
return (rnd > 1.5)? 1:-1;
}
#Override
public boolean equals(MyNeverEqualClass other){
return false;
}
#Override
public int hashCode(){
return stupidHash++;
}
}
public static void main(String[] args){
MyNeverEqualClass a = new MyNeverEqualClass(1);
MyNeverEqualClass b = new MyNeverEqualClass(1);
DupSet<MyNeverEqualClass> set = new DupSet<>();
set.add(a);
set.add(b);
}

getting an object from an arrayList with objects attribute

I have 2 classes.
public class klass1 {
String bir;
String myID;
klass1(String bir, String myID)
{
this.bir=bir;
this.myID=myID;
}
}
.
import java.util.*;
public class dd {
public static void main(String[] args) {
ArrayList<Object> ar=new ArrayList();
ar.add(new klass1("wer","32"));
ar.add(new klass1("das","23"));
ar.add(new klass1("vz","45"));
ar.add(new klass1("yte","12"));
ar.add(new klass1("rwwer","43"));
ar.remove(new klass1("vz","45"));//it's not worked!!!
System.out.println(ar.size());
}
}
What I want is removing or getting an object from array list with object's second attribute. How can I do that? Is there an easy way for it?
Just implement the equals method in the class Klass1.
public class Klass1 {
String bir;
String myID;
Klass1(String bir, String myID)
{
this.bir=bir;
this.myID=myID;
}
public boolean equals(Object o){
if(o instanceof Klass1)
return ((Klass1)o).myID.equals(myID);
else
return false;
}
}
Its because you are trying to delete a new object which isnt in the arraylist. When you use new klass1("vz","45") you are creating a new instance of this class which isnt in the arraylist.
What the system does internally is to compare those classes using equals. Why this doesn't work is explained in the following code:
Object o1 = new Object();
Object o2 = new Object();
System.out.println(o1 == o2); // false, obviously
System.out.println(o1.equals(o2)); // false
System.out.println(o1); // java.lang.Object#17046822
System.out.println(o2); // java.lang.Object#22509bfc
You can tell by the number following the # that these objects have a different hash values, and this is what the equals function of Object does check.
This is relevant for your klass, because unless you overwrite equals, you will use the equals of Object. And if you implement equals you should always implement hashcode as well. Because both tell you something about whether or not two objects are the "same", and if the one says something else than the other, some part of your code might get confused.
How to properly implement equals for your class:
#Override
public int hashCode() {
int hash = 7;
hash = 17 * hash + Objects.hashCode(this.bir);
hash = 17 * hash + Objects.hashCode(this.myID);
return hash;
}
#Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final klass1 other = (klass1) obj;
if (!Objects.equals(this.bir, other.bir)) {
return false;
}
if (!Objects.equals(this.myID, other.myID)) {
return false;
}
return true;
}
This can be done in most IDEs btw with a shortcut (i.E. alt-insert in Netbeans). Note that I did this in Java 7 using Objects. If you are in Java 6, you need to manually type(a == b) || (a != null && a.equals(b)); with the appropriate objects to compare.
Creating a proper hashcode is not always trivial, for more complex objects you might want to read a bit about hashcodes first. For simple objects: multiply primes with something.
The equals method is usually trivial, it is just important to first check for null and for class equality. This is often forgotten by programmers and a common source for NullPointerExceptions and ClassCastExceptions.

Categories