0

知りたいのですが、どうすれば 2D マップを反復処理できますか? 私はcentralMapを持っています:

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

別のマップが含まれています:

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

値として、2 つ目は「put」メソッドで作成されるため、コンストラクターには centralMap のみが含まれます。今、私はこのメソッドを再定義し、マップの完全なエントリ (2 つのキーと各要素の値) を取得したいと考えています。

public Iterator<Entry> iterator()

どのように進めればよいですか?可能であれば、問題なくイテレータを介して要素を削除するにはどうすればよいですか?

4

3 に答える 3

3

イテレータは、最初のマップのキーセットや、ネストされたマップの値(マップのコレクション)などのコレクションを操作するためのものです。iteratorrenoveメソッドが複雑な構造を理解することは期待できません。

説明したことを実行する独自の便利なメソッドを使用して、このための独自のクラスを構築することをお勧めします。

また、ここで手足を動かします。マルチマップが必要なだけではないことを確認してください。もしそうなら、例えば、グアバのHashMultimapを見てください

于 2012-05-06T17:36:44.247 に答える
2

1 つのマップを反復処理する場合と同じ手順を適用します。これを 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

2 つのキーと値を含む要素を取得する場合は、マップをネストするよりも、2 つのキーを 1 つの要素に結合し、それを 1 つのマップのキーとして使用するMap.Entryクラスを作成する方がはるかに自然です。Pair<String, String>

これを行うと、主な構造は a になり、メソッドをMap<Pair<String, String>, String>使用すると aが得られ、そこからおおよその目的を与えるイテレータを取得できます。Map.entrySet()Set<Map.Entry<String, String>, String>

Map<String, Map<String, String>>他の理由でが必要な場合は、かなり単純なコードでこれを上記の構造に変換することもできます。これは、そこから情報を取得する最も賢明な方法かもしれません。

編集注:

上記のPairクラスは基本的に と同じMap.Entryであるため、Map<Map.Entry<String, String>, String>. コードが少しわかりにくくなると思いますが、機能的に同等にすることは確かに可能です。

サンプルコード

以下のコードでは、Pairクラスを内部静的として定義し (実際の使用では、独立したクラスとして抽出することをお勧めします)、説明したようにネストされたマップを取得する変換を記述し、それを次の形式に変換します。提案し、変換されたマップのエントリでイテレータを使用して値を出力します。

もちろん、イテレータは他の用途にも使用でき、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();
      }
    }
  }

このコードは guava の他のものに依存するため、単にコピーすることはできませんが、実行する必要がある基本的なパターンを示しています。

于 2012-05-06T18:06:45.597 に答える