Dave Chen
Dave Chen

Reputation: 10975

How to combine and return enum value

I have a coordinate system such as this:

public enum Direction {
    N  ( 0,  1),
    NE ( 1,  1),
    E  ( 1,  0),
    SE ( 1, -1),
    S  ( 0, -1),
    SW (-1, -1),
    W  (-1,  0),
    NW (-1,  1);

    private int x = 0, y = 0;

    private Direction(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    public Direction combine(Direction direction) {
        //unsure
    }
}

I'm trying to combine directions with a method within the enum, like:

Direction.N.combine(Direction.E) -> should become Direction.NE
Direction.N.combine(Direction.N) -> null or Direction.N again

My thoughts are to loop through all the values in the enum, and find one that matches its x and y combined:

public Direction combine(Direction direction) {
    Direction[] directions = Direction.values();

    for (int i = 0; i < directions.length; i++)
        if (x + direction.x == directions[i].x && y + direction.y == directions[i].y)
            return directions[i];

    return this;
}

But I feel like that's an inefficient way to approach this. Is there another way to combine these directions that doesn't involve looping through all the enums?

I also want to create an uncombine function that will reverse the combine.

Direction.NE.uncombine() -> Direction[] {Direction.N, Direction.E}

I could also use the same looping technique, like:

public Direction[] uncombine() {
    Direction[] directions = Direction.values(),
                rtn = new Direction[2];

    for (int i = 0; i < directions.length; i++)
        if (x == directions[i].x && directions[i].y == 0)
            rtn[0] = directions[i];

    for (int i = 0; i < directions.length; i++)
        if (y == directions[i].y && directions[i].x == 0)
            rtn[1] = directions[i];

    return rtn;
}

So is there a more efficient way that I could try out?

Upvotes: 1

Views: 445

Answers (3)

ppawel
ppawel

Reputation: 1056

If your real class is as simply as the one from the question I think that the most efficient way would be to either manually "hardcode" or pre-calculate (e.g. in static init block) the relationship between argument and result and keep it in map and then only refer to already existing results.

Upvotes: 1

Stephen C
Stephen C

Reputation: 718826

I think that creating a Map<Direction, Direction> for each enum value is going to give you a good balance between performance and code neatness.

The combine method becomes:

    public Direction combine(Direction other) {
        return this.combinerMap.get(other);
    }

Of course, you need to build the maps during initialization of the enum class.

Returning null from this method is a bad idea because it pushes the responsibility for sanity checking back onto the caller. So I'd write it like this:

    public Direction combine(Direction other) 
            throws InsaneDirectionsException{
        Direction res = this.combineMap.get(other);
        if (res == null) {
            throw new InsaneDirectionsException(
                  "Can't combine directions " + this + 
                  " and " + other);
        }
        return res;
    }

Upvotes: 2

Oliver Gondža
Oliver Gondža

Reputation: 3511

You can keep Map<Byte, Map<Byte, Direction>> where x and y will be indexes. Once you compute new x and y, obtaining Direction will be as simple as matrix.get(x).get(y).

Upvotes: 0

Related Questions