0

我想知道:如何遍历 2D 地图?我有一个中央地图:

private final Map<String, Map<String, String>> centralMap = 
    new HashMap<String, Map<String, String>>();

其中包含另一张地图:

Map<String,String> nestedMap = new HashMap<String, String>();

作为Value,第二个是在“put”方法中创建的,所以在构造函数中,我只有centralMap。现在我想重新定义这个方法并获得地图的完整条目(2个键和每个元素的值)

public Iterator<Entry> iterator()

我应该如何进行?如果可能,如何通过迭代器删除元素而不会出现问题?

4

3 回答 3

3

迭代器旨在对集合进行操作,例如第一个映射的键集,或嵌套映射的值(映射的集合)。您不能期望迭代器 renove 方法能够理解您的复杂结构。

我建议您为此构建自己的类,并使用自己的便捷方法来执行您所描述的操作。

另外,在这里尝试一下:确保您不只是想要拥有多张地图。如果是这样,请看一下,例如,在guava 的 HashMultimap

于 2012-05-06T17:36:44.247 回答
2

您应用与迭代单个地图相同的过程,只需执行两次:

public void printNestedMap(Map<String, Map<String, String>> map)
  Iterator it = map.entrySet().iterator();
    while (it.hasNext()) {
        Map.Entry pairs = (Map.Entry)it.next(); // <- pairs.getValue() is a map
        System.out.println("Key1: " + pairs.getKey());
        //print the inner Map
        printMap((Map<String, String>)pairs.getValue());
        it.remove(); // avoids a ConcurrentModificationException
    }
}

编辑

实际上,最好将单个映射上的迭代移动到在这种情况下要调用的不同方法。

public void printMap(Map<String, String>> map)
{
   Iterator it = map.entrySet().iterator();
   while(it.hasNext())
   {
      Map.Entry pairs = (Map.Entry)it.next(); // <- pairs.getValue() is a String
      System.out.println("Key2: " + pairs.getKey() + " Value2: " + pairs.getValue());
      it.remove();
   }
}

编辑 2:测试程序

   import java.util.*;
   public class TestMap
   {
      public static void main(String[] args)
      {
         Map<String, String> innerMap              = new HashMap<>();
         Map<String, Map<String, String>> outerMap = new HashMap<>();

         innerMap.put("Key1", "Val1");
         innerMap.put("Key2", "Val2");
         innerMap.put("Key3", "Val3");
         innerMap.put("Key4", "Val4");

         outerMap.put("OuterKey1", innerMap);
         printNestedMap(outerMap);
      }

      public static void printNestedMap(Map<String, Map<String, String>> map)
      {
         Iterator it = map.entrySet().iterator();
         while (it.hasNext()) {
            Map.Entry pairs = (Map.Entry)it.next(); // <- pairs.getValue() is a map
            System.out.println("Key1: " + pairs.getKey());
            //print the inner Map
            printMap((Map<String, String>)pairs.getValue());
            it.remove(); // avoids a ConcurrentModificationException
         }
      }

      public static void printMap(Map<String, String> map)
      {
         Iterator it = map.entrySet().iterator();
         while(it.hasNext())
         {
            Map.Entry pairs = (Map.Entry)it.next(); // <- pairs.getValue() is a String
            System.out.println("Key2: " + pairs.getKey() + " Value2: " + pairs.getValue());
            it.remove();
         }
      }
   }

输出:

Key1: OuterKey1
Key2: Key2 Value2: Val2
Key2: Key1 Value2: Val1
Key2: Key4 Value2: Val4
Key2: Key3 Value2: Val3
于 2012-05-06T17:40:43.097 回答
2

如果您想获取包含两个键和值的元素,那么创建一个将两个键组合在一个元素中Map.Entry的类并将其用作单个映射中的键而不是嵌套映射实际上会更加自然。Pair<String, String>

如果这样做,您的主要结构将是 aMap<Pair<String, String>, String>并且使用该Map.entrySet()方法将为您提供 a Set<Map.Entry<String, String>, String>,您可以从中获得一个迭代器,该迭代器大致提供您所追求的内容。

如果您出于其他原因需要 a Map<String, Map<String, String>>,也可以通过相当简单的代码将其转换为上述结构,这可能是从中获取信息的最明智的方式。

编辑说明:

上面描述的Pair类本质上与 相同Map.Entry,因此您可以通过构建一个Map<Map.Entry<String, String>, String>. 我认为它使代码不太清晰,但它当然可以在功能上等效。

示例代码

在下面的代码中,我将Pair类定义为内部静态(对于实际使用,您可能希望提取为独立类),并编写了一个转换,它采用您描述的嵌套映射,将其转换为 I' ve 建议,并在转换后的映射的条目上使用迭代器来打印值。

迭代器当然可以用于其他事情,convert方法和Pair类是通用的。

import java.util.*;

public class TestMap
{
    public static void main(String[] args)
    {
        Map<String, String> innerMap1 = new HashMap<String, String>();
        Map<String, String> innerMap2 = new HashMap<String, String>();
        Map<String, Map<String, String>> outerMap = new HashMap<String, Map<String, String>>();

        innerMap1.put("InnerKey1", "Val1");
        innerMap1.put("InnerKey2", "Val2");
        innerMap1.put("InnerKey3", "Val3");
        innerMap1.put("InnerKey4", "Val4");

        innerMap2.put("InnerKey5", "Val5");
        innerMap2.put("InnerKey6", "Val6");
        innerMap2.put("InnerKey7", "Val7");
        innerMap2.put("InnerKey8", "Val8");

        outerMap.put("OuterKey1", innerMap1);
        outerMap.put("OuterKey2", innerMap2);

        Map<Pair<String, String>, String> convertedMap = convert(outerMap);
        for (Map.Entry<Pair<String, String>, String> entry: convertedMap.entrySet()) {
            System.out.println(String.format("OuterKey: %s, InnerKey: %s, Value: %s",
                    entry.getKey().getFirst(),
                    entry.getKey().getSecond(),
                    entry.getValue()
            ));
        }
    }

    private static <K1,K2,V> Map<Pair<K1, K2>,V> convert(Map<K1, Map<K2,V>> nestedMap) {
        Map<Pair<K1, K2>, V> result = new HashMap<Pair<K1, K2>, V>();
        for (Map.Entry<K1, Map<K2, V>> outerEntry: nestedMap.entrySet()) {
            final K1 outerKey = outerEntry.getKey();
            for (Map.Entry<K2, V> innerEntry: outerEntry.getValue().entrySet()) {
                final K2 innerKey = innerEntry.getKey();
                final V value = innerEntry.getValue();
                result.put(new Pair<K1, K2>(outerKey, innerKey), value);
            }
        }
        return result;
    }

    public static class Pair<T1, T2> {

        private T1 first;
        private T2 second;

        public Pair(T1 first, T2 second) {
            this.first = first;
            this.second = second;
        }

        public T1 getFirst() {
            return first;
        }

        public T2 getSecond() {
            return second;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;

            Pair pair = (Pair) o;

            if (first != null ? !first.equals(pair.first) : pair.first != null) return false;
            if (second != null ? !second.equals(pair.second) : pair.second != null) return false;

            return true;
        }

        @Override
        public int hashCode() {
            int result = first != null ? first.hashCode() : 0;
            result = 31 * result + (second != null ? second.hashCode() : 0);
            return result;
        }

    }
}

上下文中的用法说明:

在您当前的代码中,您有一个类,其中包含一个字段,该字段centralMap是旧嵌套形式的地图,以及一个用于地图大小的整数计数器。

这个包含类有一个添加条目的方法,如下所示:

@Override
public String put(final String row, final String column, final String value) {
    /**
     * Second map which is contained by centralMap, that contain Strings as Keys
     * and Values.
     */
    Map<String, String> nestedMap;

    if (centralMap.containsKey(row))
        nestedMap = centralMap.get(row);
    else
        nestedMap = new HashMap<String, String>();
    if (!nestedMap.containsKey(column))
        counter++;
    centralMap.put(row, nestedMap);
    return nestedMap.put(column, value);
}

如果根本不使用嵌套映射,而是将此字段更改为建议形式的映射,则此方法会变得更简单:

@Override
public String put(final String row, final String column, final String value) {
    Pair<String, String> key = new Pair(row, column);
    if (centralMap.contains(key)
        counter++;
    centralMap.put(key, value);
}

而且您实际上不再需要计数器,因为它始终包含与centralMap.size().

更新:

从昨天进行但现在被删除的编辑中,我现在很清楚(从编辑历史中)您想要构建一个迭代器,它以正确的顺序委托给映射的所有迭代器,并返回一个包含键和价值。

这当然是可能的,如果以后有时间,我可能会为其添加一些示例代码。正如另一个答复中指出的那样,该iterator.remove()方法可能是不可能的或不自然的。

同时,您的要求(如对同一其他回复的评论所述)与 guava's 提供的要求非常相似Table。那是开源的,看看它可能会给你一些想法。你可以在这里下载番石榴的源代码

具体来说,在 guava 中StandardTable,有一个内部类CellIterator,如下所示:

  private class CellIterator implements Iterator<Cell<R, C, V>> {
    final Iterator<Entry<R, Map<C, V>>> rowIterator
        = backingMap.entrySet().iterator();
    Entry<R, Map<C, V>> rowEntry;
    Iterator<Entry<C, V>> columnIterator
        = Iterators.emptyModifiableIterator();

    @Override public boolean hasNext() {
      return rowIterator.hasNext() || columnIterator.hasNext();
    }

    @Override public Cell<R, C, V> next() {
      if (!columnIterator.hasNext()) {
        rowEntry = rowIterator.next();
        columnIterator = rowEntry.getValue().entrySet().iterator();
      }
      Entry<C, V> columnEntry = columnIterator.next();
      return Tables.immutableCell(
          rowEntry.getKey(), columnEntry.getKey(), columnEntry.getValue());
    }

    @Override public void remove() {
      columnIterator.remove();
      if (rowEntry.getValue().isEmpty()) {
        rowIterator.remove();
      }
    }
  }

您不能只复制此代码,因为它依赖于番石榴中的其他内容,但它显示了您必须做的基本模式。

于 2012-05-06T18:06:45.597 回答