在Java(或Scala)中的HashMap的HashMap上迭代

在Java(或Scala)中的HashMap的HashMap上迭代,java,memory,scala,iterator,hashmap,Java,Memory,Scala,Iterator,Hashmap,我创建了一个类Foo,它的方法toArray()返回一个数组 现在,我有一个HashMap将字符串映射到HashMaps,它将对象映射到Foo。即: HashMap<String,HashMap<Object,Foo>> HashMap 我想创建一个类型为的新对象: HashMap<String,HashMap<Object,Array<Int>>> HashMap 这是通过为原始HashMAp中的每个元素Foo调用函数toAr

我创建了一个类
Foo
,它的方法
toArray()
返回一个
数组

现在,我有一个HashMap将字符串映射到HashMaps,它将对象映射到Foo。即:

HashMap<String,HashMap<Object,Foo>>
HashMap
我想创建一个类型为的新对象:

HashMap<String,HashMap<Object,Array<Int>>>
HashMap
这是通过为原始HashMAp中的每个元素Foo调用函数toArray()获得的

为此,我通常会做如下操作:

    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;
    }
公共静态HashMap changeMap(Map mpOld){
对象键2;
字符串键1;
迭代器it2;
HashMap mpNew=
新HashMap()
迭代器it1=mpOld.keySet().Iterator();
while(it1.hasNext()){
key1=it1.next();
it2=mpOld.get(key1.keySet().iterator();
mpNew.put(键1,new HashMap())
while(it2.hasNext()){
key2=it2.next();
mpNew.get(key1.put)(key2,mpOld.get(key1.get(key2.toArray());
//TODO清除输入mpOld.get(键1.get(键2)
}
//TODO清除输入mpOld.get(键1)
}
返回mpNew;
}
类似的代码工作得很好,但HashMap的大小太大,无法在内存中容纳其中两个。正如您所看到的,我添加了两点,希望清除一些条目。问题是,如果我这样做,就会出现并发错误,或者迭代器循环终止

我想知道是否有更好的方法来遍历地图并复制信息

另外,我在一个Scala项目中工作,但在这里我必须使用Java类型来解决一些兼容性问题。尽管
Java.util.HashMap
不是迭代器,但Scala可能有一些隐藏的功能来处理这个问题


谢谢,

我没有时间检查它,但我想类似的东西应该可以在scala地图上使用(假设您使用的是scala 2.8,它终于出现了):

它将获取外部映射,并用新映射“替换”所有内部映射,其中值是Int数组。键和地图的一般“结构”保持不变。根据“生成的贴图在不复制任何元素的情况下包装了原始贴图”,因此它不是真正的替换

如果你也做一个

import scala.collection.JavaConversions._
然后java映射可以像scala映射一样使用:包含一组可以在scala和java集合之间转换的隐式方法

BTW使用map < string,HashMap <对象,数组< int > >可能并不十分方便,如果我是你,我会考虑引入一些隐藏这个结构复杂度的类。

编辑您的评论

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)))
  }
}
印刷品:

{a={b=1}}
地图(a->地图(b->2))

显示隐式很好地应用于外部和内部映射。这就是JavaConversions对象的用途:即使您有一个java集合,也可以将其用作类似的scala类(具有增强的功能)。
您不必做任何其他事情,只需导入JavaConversion即可

集合由映射支持,因此对映射的更改将反映在集合中,反之亦然。如果在对集合进行迭代时修改映射(通过迭代器自己的移除操作除外),则迭代的结果是未定义的。该集合支持元素移除,即通过Iterator.remove、set.remove、removeAll、retainal和clear操作从映射中移除相应的映射

为什么不调用迭代器上的
remove()
方法或
set.remove(迭代器.next())
其中
iterator.next()
返回键,set是键集,迭代器是其迭代器


PS:也试着重构你的数据结构,也许是一些处理数据检索的中间类?以数组作为值的映射中的映射没有任何意义,很难跟踪。

迭代器提供了
remove(…)
方法,可以安全地删除以前访问的项。迭代映射的键/值条目,转换它们并将它们添加到新映射中,然后删除旧的

/**
 * 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());
        }
    }
}

例如,考虑字符串键;让我们调用输入数据:
Map 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
  }
}
for(条目:data.entrySet()){
String itemKey=entry.getKey();
对于(Entry innerEntry:Entry.getValue().entrySet()){
字符串innerKey=innerEntry.getKey();
对象o=innerEntry.getValue();
//不管怎样,这里有itemKey、innerKey和o
}
}

谢谢,但尽管我在项目中使用Scala,但HashMaps是Java HashMaps,因此不能对其调用MapValue。tehre是使用javaconversion解决这个问题的一种方法吗?
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
  }
}