2

I have a lookup table that should be accessed by two separate key values. One ugly way to do this is:

int[][] myArray = new int[256][256];
myArray[key1][key2] = 25;

where key1 and key2 are keys that were previously generated dynamically. But this is rather ugly. It seems that a better way to do this would be to use a Map, but those require a single key, not two. Java doesn't natively support tuples, so what should I use instead? (It also seems awkward to use an array as the key).

EDIT: The reason I say that this isn't particularly pretty is that my array is actually referenced by character values, not integers. They could be used interchangeably, but the responses to my previous question seem to suggest otherwise:

2D Array in Java, Indexed by Characters

Community
  • 1
  • 1
chimeracoder
  • 20,648
  • 21
  • 60
  • 60

3 Answers3

3

What's so ugly about that? That's about as simple as 2D matrices can be in Java, and it's quick, too.

If you really want to use a map, just defined your own Tuple class to use as a key - but be sure that you override equals() and hashCode() correctly! I'd recommend implementing an immutable Tuple class because using mutable objects as map keys can cause serious issues.

Tuple.java

package q5128376;

import java.util.Arrays;

public class Tuple<T>
{
    private T[] values;
    private int hashCode;

    private Tuple(T... values)
    {
        this.values = values;
        this.hashCode = hashCode(values);
    }

    public static <T> Tuple<T> create(T... values)
    {
        return new Tuple<T>(values);
    }

    private static <T> int hashCode(T... values)
    {
        return 31 * Arrays.hashCode(values);
    }

    @Override
    public int hashCode()
    {
        return hashCode;
    }

    @Override
    public boolean equals(Object obj) 
    {
        if (this == obj) return true;
        if (!(obj instanceof Tuple<?>)) return false;
        Tuple<?> other = (Tuple<?>) obj;
        if (!Arrays.equals(values, other.values)) return false;
        return true;
    }
}
Community
  • 1
  • 1
Matt Ball
  • 354,903
  • 100
  • 647
  • 710
  • 1
    The check for null in the equals method is redundant. `null instanceof Tuple` evaluates to false. In fact, `null instanceof Object` evaluates to false. – Adam Crume Feb 26 '11 at 17:30
  • @Adam: thanks, you're right. I forgot to remove that from the IDE-generated code, I really don't like how Eclipse does that... fixed now. – Matt Ball Feb 26 '11 at 17:31
  • @Matt Ball,Could you provide me with a main method for testing the above program.(Tuple.java) program (OR) please provide a link to ide generated source code. – Deepak Mar 07 '11 at 16:59
  • @Deepak: I do not understand what you are asking for. Do you want to download the code? [It's on github](https://github.com/mjball/Stack-Overflow-Q-A/tree/master/src/q5128376), just fork it. What do you mean by "main method for testing?" It's not a program, it's just a utility class meant to be used by other code. – Matt Ball Mar 07 '11 at 17:26
  • @mBall,Im unable to find the code there.you gave me the link but there is no code there.unable to locate the code.can you give the directions. – Deepak Mar 08 '11 at 11:44
  • @Deepak: the code is the same as the code posted in my answer above. Or, click the link `Tuple.java` in the link I provided above, or [here's](https://github.com/mjball/Stack-Overflow-Q-A/blob/master/src/q5128376/Tuple.java) a direct link to it. Are you not familiar with github? – Matt Ball Mar 08 '11 at 12:44
  • @Matt Ball.im not able to see the source code for Tuple.java when i click the above link,is there some problem ? One more thing,How do i test the utility class with some test data,can you include that test program as well.Sorry for bothering you again – Deepak Mar 08 '11 at 12:54
  • @Deepak: it's **exactly the same** as what's in my answer. – Matt Ball Mar 08 '11 at 12:57
  • @Matt,One more thing,How do i test the utility class with some test data,can you include that test program as well.Sorry for bothering you again – Deepak Mar 08 '11 at 12:59
  • @Deepak: what do you want to test? Is it that you don't understand how this class is used? Also, you don't need to "@Matt" me; since your comment is on my own answer, I'll be notified without the @name :) – Matt Ball Mar 08 '11 at 13:17
  • sorry if its offending you,i used names as others used.well i dont know how to run the `Tuple.java` program on stand alone machine.hope you understand now,I know its a utility class but how could i run `test data` on `Tuple.java` to check its functionality – Deepak Mar 08 '11 at 13:26
2

Your solution does not seem very ugly to me... It's very fast, at the expense of a little memory usage (64 K ints).

An alternative would be to define a Pair class to use as a key for a map.

Yet another solution would be to define a map that maps ints to a map mapping ints to int values:

Map<Integer, Map<Integer, Integer>> map;

However, this would require the creation of a lot of map objects.

The best approach depends on how sparse your lookup table is.

ChrisJ
  • 5,161
  • 25
  • 20
  • 1
    @thebackhand : Note that your Pair class should override equals and hashCode to work correctly. I recommend using apache commons-lang EqualsBuilder and HashCodeBuilder to implement them easily and correctly. Also, make your Pair class immutable. – JB Nizet Feb 26 '11 at 17:12
  • I strongly approve your comment, JB Nizet! – ChrisJ Feb 26 '11 at 17:13
  • See my answer for a generic n-tuple implementation. – Matt Ball Feb 26 '11 at 17:22
0

I agree with ChrisJ that your 2 dimensional array is not bad at all.

You could have a Map of a Map, like

Map<Integer, Map<Integer, Integer>> myMap;

But that can get even more ugly than your 2d array idea.


Alternatively, you could convert two int keys into one String key, like

Map<String, Integer> myMap = new HashMap<String, Integer>();
int key1 = 3;
int key2 = 4;
int value = 25;
myMap.put(key1 + "/" + key2, value);

But I recommend going with the solution you have, if you can guarentee that the highest value for either key is 255.

Community
  • 1
  • 1
Zach L
  • 16,072
  • 4
  • 38
  • 39