Creating a Hash table with a tuple as a key - java

As the title says i want to create a Hash table that takes tuples of integers as keys.What i have don so far:
class Tuple {
public Tuple (int x, int y) {
this.x = x;
this.y = y;
}
public int k;
#Override
public int hashCode() {
int hash = 17;
hash = 31 * hash + this.x;
hash = 31 * hash + this.y;
return hash;
}
private int x;
private int y;
}
public class Class1{
public static void main(String[] args){
Tuple t= new Tuple (1,1);
HashMap<Tuple, Integer> seen = new HashMap<Tuple, Integer>();
seen.put(t,33);
System.out.println(seen.get(t));
}
}
My problem is this: I would like to acquire the value 33 only by knowing the tuple (1,1) and not actually knowing the object t.
Something like seen.get((1,1)) and have the value 33.
How could this be achieved?

You would do
System.out.println(seen.get(new Tuple(1, 1));
The key concept is that since you override equals and hashCode any Tuple object that satisfies equality and hashCode equality will work as a key, and not just the t object.
Edit:
Note that your Tuple class also must override the public boolean equals(Object o) method in a correct fashion for any of this to work correctly:
public class Tuple {
private int x;
private int y;
public Tuple(int x, int y) {
this.x = x;
this.y = y;
}
#Override
public int hashCode() {
int hash = 17;
hash = 31 * hash + this.x;
hash = 31 * hash + this.y;
return hash;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Tuple other = (Tuple) obj;
if (x != other.x)
return false;
if (y != other.y)
return false;
return true;
}
}
Then test with:
public static void main(String[] args) {
Tuple t = new Tuple(1, 1);
Map<Tuple, Integer> seen = new HashMap<Tuple, Integer>();
seen.put(t, 33);
System.out.println(seen.get(t));
System.out.println(seen.get(new Tuple(1, 1)));
}

Actually, you can use any key for the map if:
key is immutable;
key implements equals() and hashCode().
In your example, you have to use Tuple instance. You already could know it or create the new one with known x and y (and this new instance will be absolutely the same key because all values x and y are used in equals() and hashCode() are also the same).
// It's better to make class immutable
public final class Tuple {
private final int x;
private final int y;
public static Tuple of(int x, int y) {
// you can add internal cashe here
return new Tuple(x, y);
}
private Tuple(int x, int y) {
this.x = x;
this.y = y;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!(obj instanceof Tuple))
return false;
return x == ((Tuple)obj).x && y == ((Tuple)obj).y;
}
#Override
public int hashCode() {
return Objects.hash(x, y);
}
}
Demo
Map<Tuple, Integer> map = new HashMap<>();
map.put(Tuple.of(1, 1), 33);
System.out.println(map.get(Tuple.of(1, 1))); // 33

Related

I have got a list of pairs how can i check whether the list contains a specific element or not.The list.contains function is always giving false

I have created a pair class and list of objects of this class. how can i check whether the list contains a object or not
i have tried list.contains method
//the pair class
public static class pair
{
int x,y;
public pair(int x,int y)
{
this.x=x;
this.y=y;
}
public int getY() {
return y;
}
public int getX() {
return x;
}
}
//this line is always giving false as output
if (!l.contains(new pair(x-1,y)))
count_1++;
By default, objects in Java are only equal if the instances are the same (when you say new Pair() you're making a new instance!).
We can override this behavior by overriding the equals() method of your Point class. Like so:
public class Point {
private final x;
private final y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
private static boolean isPoint(Object o) {
return o != null && o instanceof Point;
}
private boolean coordsEqual(Point p) {
return getX() == p.getX() && getY() == p.getY();
}
public boolean equals(Object o) {
return isPoint(o) && coordsEqual((Point) o); //is o is a point? Does it have equal coords?
}
Now Point.equals() will return true if our coordinates match instead of the default object equals behavior. Since Collection.contains() uses the equals() method to check for equality, your code will behave as expected.
You'll need to write an equals method in your Pair class, so that the List can work out whether it contains the Pair that you're looking for. The List will use your equals method when looking for matches.
The simplest way to write your equals method is to let your IDE generate it for you.

Return number of edges of each vertex in a digraph (jgrapht)

I have a digraph created using:
public static DirectedGraph<Point, DefaultEdge> directedGraph = new DefaultDirectedGraph<Point, DefaultEdge>(DefaultEdge.class);
void setup() {
Point myPoint = new Point(x, y);
Point myNextPoint = new Point(xToFillNext, yToFillNext);
directedGraph.addVertex(myPoint);
directedGraph.addVertex(myNextPoint);
directedGraph.addEdge(myPoint, myNextPoint);
Point mySecondPoint = new Point(x, y);
Point mySecondNextPoint = new Point(xToFillNext, yToFillNext);
directedGraph.addVertex(mySecondPoint);
directedGraph.addVertex(mySecondNextPoint);
directedGraph.addEdge(mySecondPoint, mySecondNextPoint);
System.out.println("#vertices: "+ directedGraph.vertexSet());
}
public static class Point {
public int x;
public int y;
public Point(int x, int y)
{
this.x = x;
this.y = y;
}
#Override
public String toString() {
return ("[x="+x+" y="+y+"]");
}
#Override
public int hashCode() {
int hash = 7;
hash = 71 * hash + this.x;
hash = 71 * hash + this.y;
return hash;
}
#Override
public boolean equals(Object other)
{
if (this == other)
return true;
if (!(other instanceof Point))
return false;
Point otherPoint = (Point) other;
return otherPoint.x == x && otherPoint.y == y;
}
}
I would like to get the number of outwards edges per vertex using:
directedGraph.outDegreeOf()
but I don't want to do it vertex per vertex (this is a simple code to make it easier to go through it, in my whole program I have many more vertices) and I'd like to go through the vertex set and return the number of outwards edges for each vertex of the set automatically, no matter how many vertices there are.
How should I proceed to do this ?
(I use processing which is based on java)
Check out the JGrapht API.
The DirectedGraph interface contains a vertexSet() function. You can use this to iterate over the vertexes you've added, and you can get the outDegreeValue() of each one:
for(Point p : directedGraph.vertexSet()){
int degree = directedGraph.outDegreeOf(p);
System.out.println("Degree of " p.toString() + ": " + degree);
}
I am not sure if DirectedGraph stores this information inherently or not, but you can easily store this information while adding the edge, by using a hasmap.
HashMap<Integer,Integer> outEdgesMap = new HashMap<Integer,Integer>();
you are doing
directedGraph.addEdge(myPoint, myNextPoint);
after this also do
outEdgesMap.put(myPoint,outEdgesMap.getOrDefault(myPoint,0)+1);
Just to be clear, it will be
directedGraph.addEdge(myPoint, myNextPoint);
outEdgesMap.put(myPoint,outEdgesMap.getOrDefault(myPoint,0)+1);
So your directedGraph.outDegreeOf() will be
for(Integer i : outEdgesMap.keySet()){
sout(i+ " : " +outEdgesMap.get(i) );
}

Accessing a HashMap value with a custom Pair Object as a key

I'm new to Java. I'm writing a 2d game and I've decided to use a HashMap to store my map data because I need to support negative indices for my map coordinates. This is because the size of the map can grow during the game.
I have written a custom Pair class that stores final x and y values. I am using this Pair object as my key for my HashMap. My values are instances of a custom Cell class.
I have declared my HashMap as follows:
HashMap<Pair, Cell> tiles = new HashMap<Pair, Cell>();
Next, I add entries to my map using:
tiles.put(new Pair(0,0), new Cell());
0,0 is obviously my unique x,y coordinate for this cell.
How do I access the fields and methods of Cell using the .get() method of HashMap, specific to an individual Pair? Such as Pair(0,0) or Pair(0,1). If the key was simply a string or an int, I would have no problem. I just can't figure out how to format my key for an object with a specific coordinate.
You need to override the equals and hashCode method of the Pair class. Right now, if you have two instances of Pair as such:
Pair p1 = new Pair(0,0);
Pair p2 = new Pair(0,0);
These two instances in your program would not be seen as equal, and hence if you said:
tiles.put(p1, XXX);
tiles.put(p2, YYY);
the behavior would be such that your map would have two distinct keys, with two distinct values - where I believe what you would want is one key, with the last value YYY after these statements execute.
After implementing hashCode and equals, you could write a static helper method that instantiates a new Pair with some given coordinates, and performs a map lookup:
static Cell lookup(int x, int y) {
return tiles.get(new Pair(x, y));
}
Here's a basic Pair class to help you get started:
public class Pair {
private final int x;
private final int y;
public Pair(final int x, final int y) {
this.x = x;
this.y = y;
}
#Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Pair)) {
return false;
}
final Pair pair = (Pair) o;
if (x != pair.x) {
return false;
}
if (y != pair.y) {
return false;
}
return true;
}
#Override
public int hashCode() {
int result = x;
result = 31 * result + y;
return result;
}
}
You just write tiles.get(new Pair(0, 0)), just like you did for put.
You will need to override the methods .equals() and .hashCode() for your Pair() type. They are needed in order to use a type in a HashMap. Equals can just check that the 2 values are equal:
#Override public boolean equals(Object o) {
if(this == o) return true;
if(!(o instanceof Pair)) return false;
Pair p = (Pair)o;
return p.x == x && p.y == y;
}
For hashCode, you must generate a value that is unique:
private volatile int hashCode; // define this as a member of the class
#Override public int hashCode() {
int result = hashCode;
if(result == 0) {
result = 17 * x + 31 * y;
hashCode = result;
}
return result;
}
Then you can access the cell at (0, 0) by simply calling
tiles.get(new Pair(0, 0));
You need to override hashCode(). Something like:
public int hashCode() {
return 17 * this.key + 31 * this.value;
}

Java HashSet contains function not working

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

LinkedHashSet Not Removing Duplicates

I am trying to create a search algorithm that stores coordinate pairs in a wrapper class called HashSquareSpec. In order to avoid duplicates, and maintain insertion order, I am inserting each HashSquareSpec into a LinkedHashSet. Even though I have overridden the equals() method and hashCode() methods, the LinkedHashSet still accepts two HashSquareSpec objects with
the same coordinate pairs.
public static void main(String [] args)
{
LinkedHashSet<HashSquareSpec> firedShots = new HashLinkedSet<HashSquareSpec>();
HashSquareSpec a = new HashSquareSpec(1,2);
HashSquareSpec b = new HashSquareSpec(2,2);
HashSquareSpec c = new HashSquareSpec(1,2);
HashSquareSpec d = new HashSquareSpec(3,2);
firedShots.add(a);
firedShots.add(b);
firedShots.add(c);
firedShots.add(d);
System.out.println(a.equals((SquareSpec)c));
Iterator l = firedShots.iterator();
while(l.hasNext())
{
System.out.println(l.next().hashCode());
}
}
Output:
true
38444474
38474265
38444474
38504056
HashSquare class
public class HashSquareSpec extends SquareSpec
{
public HashSquareSpec(int sx, int sy)
{
super(sx,sy);
}
public HashSquareSpec(String codeString)
{
super(codeString);
}
#Override
public int hashCode()
{
return this.toString().hashCode();
}
public boolean equals(HashSquareSpec other)
{
if(this.toString().equals(other.toString()))
return true;
else
return false;
}
}
and the super class of HashSquareSpec
public class SquareSpec {
public int x;
public int y;
public SquareSpec(int sx, int sy) {
this.x = sx;
this.y = sy;
}
public SquareSpec(String codeString) {
this.x = Integer.parseInt(codeString.substring(1,2));
this.y = Integer.parseInt(codeString.substring(3,4));
}
public String toString() {
return("(" + x + "," + y + ")");
}
public boolean equals(SquareSpec other) {
return (other.x == this.x &&
other.y == this.y );
}
}
Despite many different hashCode variations and Eclipse equals and hashCode generation, the
firedShots data structure keeps accepting duplicates. What is wrong with my code?
You are on the right track, overriding hashcode and equals, except you are incorrectly overriding the equals method from Object in HashSquareSpec (and SquareSpec). The parameter must be an Object. Because it's not overridden, equals from Object is called, which compares object references to see if they're the same object. They aren't, so the "duplicate" is allowed.
Try:
#Override
public boolean equals(Object other)
{
if(this.toString().equals(other.toString()))
return true;
else
return false;
}
You should also test if other is null and then ensure that other is the same type.
Include the #Override annotation so that the compiler will complain if the method doesn't actually override anything.
It's still accepting because you are not overriding the equals method. You need to override boolean equals(Object). The problem is that you're defining a new method like boolean equals(SquareSpec).
Here is the method that LinkedHashSet#add(T) eventually invokes:
HashMap#put(K, V):
#Override public V put(K key, V value) {
if (key == null) {
return putValueForNullKey(value);
}
int hash = secondaryHash(key.hashCode());
HashMapEntry<K, V>[] tab = table;
int index = hash & (tab.length - 1);
for (HashMapEntry<K, V> e = tab[index]; e != null; e = e.next) {
if (e.hash == hash && key.equals(e.key)) {
preModify(e);
V oldValue = e.value;
e.value = value;
return oldValue;
}
}
As you can see, it compares using hashCode and equals(Object).

Categories