0

I'm implementing the WeightedSlopeOne prediciton algorithm for recommender system and at some point in the code I need to have 2 2D maps, one Map<Integer, Map<Integer, Integer>> and one Map<Integer, Map<Integer, Double>>

As you can understand accessing these and assigning values is a cumbersome procedure:

//The following 20 lines are 1 line in Python. Sigh...
HashMap<Integer, Integer> freqsForItem1 = frequencies.get(curItemID);
//See if we have a value for curItemID
if (freqsForItem1 == null) {
    freqsForItem1 = new HashMap<Integer, Integer>();
    freqsForItem1.put(curItemID_2, 1);
    frequencies.put(curItemID, freqsForItem1);
}
else {//See if we have a value for curItemID+curItemID_2
    Integer freqForItem1Item2 = freqsForItem1.get(curItemID_2);
    if (freqForItem1Item2 == null) {
        //If we don't have a value for item1+item2 we just put 1
        freqsForItem1.put(curItemID_2, 1);
    }
    else {//We already have a value for curItemID+curItemID_2
        //So we just increment it
        freqsForItem1.put(curItemID_2, freqForItem1Item2 + 1);
    }
}

So what should I be using here instead of a Map<K1, Map<K2, V>>, or if there is no better data structure available what is a better way to access and change the values of such a Map?

Bar
  • 2,736
  • 3
  • 33
  • 41

3 Answers3

2

You can use Table from Google's Guava to do this without worrying of implementation.

Check Guava Page: https://code.google.com/p/guava-libraries/wiki/NewCollectionTypesExplained#Table

Michal Borek
  • 4,584
  • 2
  • 30
  • 40
  • 1
    As Jack said above: "A Multimap should be equivalent to a Map> (eg multiple values for a key), not to what the OP needs (eg two levels of keys) " – Bar May 08 '13 at 13:32
  • @Bar I have not answered about "Multimap" but "Table", these are entirely different classes! – Michal Borek May 08 '13 at 13:37
  • 1
    @MichalBorek I think this bit of the docs makes it clear that a `Table` is very map-like: "`rowMap()`, which views a `Table` as a `Map>`. Similarly, `rowKeySet()` returns a `Set`." – Matt Ball May 08 '13 at 13:38
  • @MichalBorek you're right sorry. Still, I was hoping for a solution that doesn't use external libraries so I chose the other answer. Upvoted for visibility though. – Bar May 08 '13 at 19:27
2

Instead of using a map of maps, you can create a new, immutable class (with properly implemented equals() and hashCode() methods!) that stores the two integer keys, and use that as the key for a simpler map.

class MyKey {
    int first;
    int second;
    // etc...
}

Map<MyKey, Integer> freqs = new HashMap<MyKey, Integer();

This will greatly simplify accessing & assigning values, and even moreso if you decide you need to make your key more complex.

Community
  • 1
  • 1
Matt Ball
  • 354,903
  • 100
  • 647
  • 710
-1

so your key is an integer in both dimensions. why dont you use a

HashMap<Integer, Double> [] 

instead? or at least an

ArrayList<HashMap<Integer, Double>>

Would be much more performant

desperateCoder
  • 700
  • 8
  • 18
  • Why do you think this would provide better performance? I don't think the OP is concerned with code performance, anyway, so much as complexity of the code that uses the data structure. – Matt Ball May 08 '13 at 13:28
  • because a comparison of two objects (Integer) by hash is much slower than a plain comparison between two ints. maybe i misunderstood something, but i think efficiency includes performance. – desperateCoder May 08 '13 at 13:32
  • Any "slowness" in the code is not going to arise from that, here. – Matt Ball May 08 '13 at 13:39