Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using string tuples as key for HashMap [duplicate]

I need Java equivalent for following Python:

In [1]: d = {}
In [2]: k = ("x","2")
In [3]: d[k] = 1
In [4]: print d[("x","y")]
1

Python has tuples which are hashable. I tried following in Java unsuccessfully:

Map<String[], Integer> d = new HashMap<String[], Integer>();
String[] k = new String[]{"x", "y"};
d.put(k, 1);
System.out.println(d.get(k));
System.out.println(d.get(new String[]{"x", "y"}));

It outputs:

1
null

This means reference to String[] is getting hashed instead of the value.

An inefficient way I can think of is concatenating elements from String[] into a single String.

Is there a better way?

like image 952
Nullpoet Avatar asked Nov 06 '13 05:11

Nullpoet


People also ask

Can you use a tuple as a key in a HashMap?

Yes, a tuple is a hashable value and can be used as a dictionary key. A tuple would be useful as a key when storing values associated with a grid or some other coordinate type system. The following code example shows a dictionary with keys representing a simple x,y grid system.

Can we have a duplicate key value in HashMap?

HashMap stores key, value pairs and it does not allow duplicate keys. If the key is duplicate then the old key is replaced with the new value.

Can a tuple be key for map?

Tuples can be used as keys if they contain only strings, numbers, or tuples; if a tuple contains any mutable object either directly or indirectly, it cannot be used as a key.

Does HashMap allow duplicate key allow then how you get value for corresponding key?

If you try to insert the duplicate key, it will replace the element of the corresponding key. HashMap is similar to HashTable, but it is unsynchronized. It allows to store the null keys as well, but there should be only one null key object and there can be any number of null values.


3 Answers

HashMaps use Object.hashCode() to create the hash. This, by default, uses a hash of the object that is unique for each instance - but doesn't look into any contents.

You migth want to create a tuple that overrides hashCode() and, in addition to that, is immutable once created:

public class Tuple<T> {
    private final T[] contents;

    public Tuple (T[] contents) {
        if (contents.length != 2)
            throw new IllegalArgumentException();
        this.contents = contents;
    }

    public T[] getContents () {
        return this.contents.clone();
    }

    @Override
    public int hashCode () {
        return Arrays.deepHashCode(this.contents);
    }

    @Override
    public boolean equals (Object other) {
        return Arrays.deepEquals(this.contents, other.getContents());
    }

    @Override
    public String toString () {
        return Arrays.deepToString(this.contents);
    }
}

[Edit]: Note that, if mutable objects are used instead of strings, the getter must perform a deep copy, not just a simple clone() to ensure immutability.

like image 151
Johannes H. Avatar answered Oct 20 '22 22:10

Johannes H.


Arrays in Java don't provide hashCode() and equals(Object) methods, so they aren't appropriate as map keys. What you could use instead is Arrays.asList(string1, string1, etc) which would give you an immutable List, which all the methods needed for a Map's key.

like image 22
Mureinik Avatar answered Oct 21 '22 00:10

Mureinik


You could use Arrays.toString(myArray) as your key.

like image 29
user949300 Avatar answered Oct 20 '22 22:10

user949300