Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Iterating over a HashMap of HashMaps in Java (or Scala)

I created a class Foo that has the method toArray() that returns an Array<Int>.

Now, I have a HashMap mapping Strings to HashMaps, which map Objects to Foo. That is:

HashMap<String,HashMap<Object,Foo>>

And I want to create a new object of type:

HashMap<String,HashMap<Object,Array<Int>>>

That is obtained by calling the function toArray() for every element Foo in the original HashMAp.

To do so I normally would do something like:

    public static HashMap<String,HashMap<Object,Array<Int>>> changeMap(Map mpOld) {
        Object key2;
        String key1;
        Iterator it2;
        HashMap<String,HashMap<Object,Array<Int>>> mpNew= 
            new HashMap<String,HashMap<Object,Array<Int>>>()
        Iterator it1 = mpOld.keySet().iterator();
        while (it1.hasNext()) {
            key1=it1.next();
            it2= mpOld.get(key1).keySet().iterator();
            mpNew.put(key1,new HashMap<Object,Array<Int>>())
            while (it2.hasNext()) {
                key2=it2.next();
                mpNew.get(key1).put(key2,mpOld.get(key1).get(key2).toArray());
                //TODO clear entry mpOld.get(key1).get(key2)
            }
            //TODO clear entry mpOld.get(key1)
        }
        return mpNew;
    }

A similar code works just fine, but the Size of the HashMap is too big to hold two of them in memory. As you can see I added two points where I want to clear some entries. The problem is, if I do, I get either a concurrency error, or the iterator loop just terminates.

I wonder if there is a better way to iterate through the Maps and copy the information.

Also, I'm working in a Scala project but here I have to use Java types for some compatibility issues. Although Java.util.HashMap is not an iterator, maybe Scala has some hidden functinality to deal with this?

Thanks,

like image 659
Skuge Avatar asked Jul 15 '10 09:07

Skuge


People also ask

Can you iterate through a HashMap Java?

In Java HashMap, we can iterate through its keys, values, and key/value mappings.

What is difference between map and HashMap in Scala?

Scala map is a collection of key/value pairs. Any value can be retrieved based on its key. Keys are unique in the Map, but values need not be unique. HashMap implements immutable map and uses hash table to implement the same.

How does HashMap work in Scala?

Scala HashMap is used to store objects and it take the object in the form of key value pair. For every value there should be one key associated with it. Scala collection contains this Hashmap and it is the implementation of MAP.


3 Answers

Iterators offer remove(..) methods that safely removes the previously accessed item. Iterate over the Key/Value entries of the map, converting them and adding them to the new map, and removing the old ones as you go.

/**
 * Transfers and converts all entries from <code>map1</code> to 
 * <code>map2</code>.  Specifically, the {@link Foo} objects of the 
 * inner maps will be converted to integer arrays via {@link Foo#toArray}.
 * 
 * @param map1 Map to be emptied.
 * @param map2 Receptacle for the converted entries.
 */
private static void transfer(Map<String, Map<Object, Foo>> map1
        , Map<String, Map<Object, int[]>> map2) {

    final Iterator<Entry<String, Map<Object, Foo>>> mapIt
        = map1.entrySet().iterator();
    while (mapIt.hasNext()) {
        final Entry<String, Map<Object, Foo>> mapEntry = mapIt.next();
        mapIt.remove();
        final Map<Object, int[]> submap = new HashMap<Object,int[]>();
        map2.put(mapEntry.getKey(), submap);
        final Iterator<Entry<Object,Foo>> fooIt 
            = mapEntry.getValue().entrySet().iterator();
        while (fooIt.hasNext()) {
            final Entry<Object,Foo> fooEntry = fooIt.next();
            fooIt.remove();
            submap.put(fooEntry.getKey(), fooEntry.getValue().toArray());
        }
    }
}
like image 94
Gunslinger47 Avatar answered Nov 14 '22 21:11

Gunslinger47


I did not have time to check it, but I guess something like this should work on scala Maps (assuming you use scala 2.8 which is finally here):

mpO.mapValues(_.mapValues(_.toArray))

It would take your outer map, and "replace" all inner maps with a new one, where the values are the Int arrays. Keys, and the general "structure" of the maps remain the same. According to scaladoc "The resulting map wraps the original map without copying any elements.", so it won't be a real replacement.

If you also do an

import scala.collection.JavaConversions._

then the java maps can be used the same way as scala maps: JavaConversions contain a bunch of implicit methods that can convert between scala and java collections.

BTW using a Map < String,HashMap < Object,Array < Int>>> might not be really convenient at the end, if I were you I would consider introducing some classes that would hide the complexity of this construct.

Edit reflecting to your comment

import scala.collection.JavaConversions._
import java.util.Collections._

object MapValues {
  def main(args: Array[String]) {
    val jMap = singletonMap("a",singletonMap("b", 1))
    println(jMap)
    println(jMap.mapValues(_.mapValues(_+1)))
  }
}

prints:

{a={b=1}}
Map(a -> Map(b -> 2))

Showing that the implicits are applied both to the outer and inner map quite nicely. This is the purpose of the JavaConversions object: even if you have a java collection you can use it as a similar scala class (with boosted features).
You don't have to do anything else, just import JavaConversions._

like image 24
Sandor Murakozi Avatar answered Nov 14 '22 20:11

Sandor Murakozi


For example considering String keys; lets call the input data: Map<String, Map<String, Object>> data

for (Entry<String, Map<String, Tuple>> entry : data.entrySet()) {
  String itemKey = entry.getKey();
  for (Entry<String, Object> innerEntry : entry.getValue().entrySet()) {
    String innerKey = innerEntry.getKey();
    Object o = innerEntry.getValue();
    // whatever, here you have itemKey, innerKey and o
  }
}
like image 45
Manu Avatar answered Nov 14 '22 22:11

Manu