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.

6
  • You can store Lists in a hashmap. Commented Feb 22, 2015 at 23:33
  • You can use any object as the key for a hashmap, for your purposes instead of using an int array you could use a List<Integer> Commented Feb 22, 2015 at 23:34
  • 1
    Either a List or wrap your arrays in a simple class which overrides equals()/hashCode(); see the Arrays class Commented Feb 22, 2015 at 23:38
  • you should take a look at the Trove library. It supports primitive collections, maps and custom hashing strategies. Commented Feb 22, 2015 at 23:45
  • 1
    what anyone think about hashset? Commented Feb 23, 2015 at 0:00

4 Answers 4

7

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] ...

        }
 }
Sign up to request clarification or add additional context in comments.

2 Comments

You can make use of Arrays.hashCode() and Arrays.equals() for your two functions.
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 ?
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.

Comments

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

Comments

-2

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

6 Comments

Gregory Basior answer is more Java-ish.
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 It is perfectly OK to produce the same hash value for two arrays, as long as their content is the same. See documentation for more details
@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 Can you give a code example that support your theory?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.