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

Ray Rackiewicz Source

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.

javahashmap

Answers

answered 3 years ago Louis Wasserman #1

You just write tiles.get(new Pair(0, 0)), just like you did for put.

answered 3 years ago sturcotte06 #2

You need to override hashCode(). Something like:

public int hashCode() {
    return 17 * this.key + 31 * this.value;
}

answered 3 years ago Amir Afghani #3

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

answered 3 years ago gla3dr #4

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

comments powered by Disqus