7

I have a function that does some calculations. It accepts a int array and returns an integer based on the contents of the int array that's passed to it.

As my application is doing hundreds of theses calculations I'm trying to set up a way to store those calculation results in a hashmap so it don't have to recalculate the calculation it already did recently. To do this though I'd need to use the int arrays as my keys to the hashmap.

At the moment this is printing size 2, I want it to be printing size 1:

LinkedHashMap hashmap = new LinkedHashMap();

int test[] = {1,2,3};
int test2[] = {1,2,3};

hashmap.put(test, 1);
hashmap.put(test2, 1);

System.out.println("Size: "+hashmap.size());

What's the best way to achieve this? I could create a method to convert the arrays to some kind of string encoding the arrays data but I don't think that would be the best solution.

user11406
  • 1,208
  • 1
  • 13
  • 25

4 Answers4

6

It is currently printing 2 because they are two different arrays with two different hashCodes, so although they have the same elements, they are not the same for the purposes of a set. You should create your own object which has an array as a variable inside of the Object. Then it will override the equals and hashCode method so that the value will be the same based on the values in the array.

e.g.:

 public class MyClass
 {
        private int[] array;

       public boolean equals(Object o)
       {
           if(! (o instance of MyClass) ) return false;
           //loop through the arrays to see they are equal
         }

        public int hashCode()
       {  
           //loop through the array and return a number that is based off of the values in the array such as array[0] ^ array[1] + array[2] * array[3] / array[4] ...

        }
 }
Gregory Basior
  • 300
  • 1
  • 9
  • 5
    You can make use of `Arrays.hashCode()` and `Arrays.equals()` for your two functions. – Pham Trung Feb 23 '15 at 02:48
  • For some reason I do not see this solution working. First, as per author question there are hundreds of arrays to process. This solution will create an object for each array which may be hard on a memory (if big number of different arrays are involved) and eventually crash the program. Second there will be a problem to efficiently access the array hashCode in that blog of objects. And thirdly, the solution does not provide a way to store the array calculation result. So what's cooking ? – Sigismundus Feb 24 '15 at 23:22
0

Use Apache commons StringUtils.join() method to create unique array key. It takes an array as a parameter and calls toString() on each element to get each elements string representation. Each elements string representation is then joined into one string with a separator in between if one is specified:

import org.apache.commons.lang3.StringUtils;

int[] a = {1, 2, 3}
String key= StringUtils.join(a, '-');
System.out.println(key);

Produces:

1-2-3

Sigismundus
  • 635
  • 4
  • 15
0

As others have suggested, you should create a class that wraps the array and implements hashCode() and equals() in a consistent way.

Other answers either suggest to convert your int[] array into a String or indicate you should iterate over it to calculate a hash value or check for equality.

I suggest you use Java's Arrays utility class to efficiently calculate an array-based hash value and check for array equality:

public class Key {

    private final int[] values;

    public Key(int[] values) {
        this.values = values;
    }

    @Override
    public boolean equals(Object another) {
        if (another == this) {
            return true;
        }
        if (another == null) {
            return false;
        }
        if (another.getClass() != this.getClass()) {
            return false;
        }
        Key key = (Key) another;
        return Arrays.equals(this.values, key.values);
    }

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

Then, use it in your map:

Map<Key, Integer> map = new LinkedHashMap<>(); // preserve insertion order?

int test[] = {1, 2, 3};
int test2[] = {1, 2, 3};

Key key = new Key(test);
Key key2 = new Key(test2);

map.put(key, 1);
map.put(key2, 1);

map.size(); // 1

Note: This implementation of Key takes the array's elements order into account, meaning that two Keys will be different if constructed from two arrays with the same elements in different order:

int[] v1 = {1, 2, 3};
int[] v2 = {2, 1, 3};

Key k1 = new Key(v1);
Key k2 = new Key(v2);

k1.equals(k2); // false!

If you want two Keys to be equal despite their array's elements order, you should turn the int[] array into a HashSet in the Key class's constructor and then implement Key's equals() and hashCode() methods by delegating to their respective implementations in the HashSet.

fps
  • 33,623
  • 8
  • 55
  • 110
-1

I would create array specific key, and then store in the cache that key and the calculated result:

public static void main() {
   Map<String, Integer> hashmap = new HashMap<>();
   int[] arr1 = {1, 2, 3};
   int[] arr2 = {1, 2, 3};
   hashmap.put(Arrays.hashCode(arr1), 1);
   hashmap.put(Arrays.hashCode(arr2), 1);
   System.out.println("Size: "+hashmap.size());
}

The code prints Size: 1

MaxZoom
  • 7,619
  • 5
  • 28
  • 44
  • Gregory Basior answer is more Java-ish. – m0skit0 Feb 23 '15 at 00:31
  • This is not correct as its possible the hashCode for two different arrays produces the same value. This is where the equals operation of the key is used to split the difference, but no custom equals operation can be provided with this approach. – Solubris Feb 14 '19 at 07:46
  • @Solubris It is perfectly OK to produce the same hash value for two arrays, as long as their content is the same. See [documentation](https://docs.oracle.com/javase/8/docs/api/java/util/Arrays.html#hashCode-int:A-) for more details – MaxZoom Feb 19 '19 at 19:50
  • @MaxXoom I said that two different arrays could have the same hash code, this is where the value of the elements in the array could be used to separate the keys, but since only the hash code is used as the key the elements of the array are not available for any hash look up the hash map does. – Solubris Feb 20 '19 at 20:58
  • @Solubris Can you give a code example that support your theory? – MaxZoom Feb 21 '19 at 00:07
  • See this answer for an example of hash code clashes: https://stackoverflow.com/questions/1381060/hashcode-uniqueness – Solubris Feb 22 '19 at 19:24