2012-05-06 11 views
0

私は2Dマップをどのように反復処理できますか?コンストラクタで、私はちょうど持っているように、値としてネストされたマップ内のJavaイテレータ(マップ2D)

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

、2つ目「置く」方法で作成されます。別のマップが含まれてい

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

:私はcentralMapを持っていますcentralMap。今度はこのメソッドを再定義し、マップの完全なエントリを取得したい(2つのキーと各要素の値)

public Iterator<Entry> iterator() 

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

+0

すべてのネストされたマップのすべてのエントリを通過するイテレータが必要ですか?それですか? –

+0

はい、どうぞ! – ZelelB

答えて

3

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

あなたの説明したような独自の便利な方法で、独自のクラスを作成することをお勧めします。

また、ここでは:マルチマップをしたいだけではないことを確認してください。もしそうなら、

+1

実際、これは 'Multimap'よりGuava' Table'のように見えます。この行の中の –

2

guava's HashMultimapであなたは、単一のマップを反復処理しているかのように同じ手順を適用し、例えば、見て、あなたは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 
    } 
} 

EDIT

このシナリオで呼び出される別のメソッドに、1つのマップ上の反復を移動する方が実際には良いでしょう。

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

EDIT 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 
+0

は、 'Iterator it2 = pairs.getValue()。entrySet()。iterator();' コンパイルの問題があります.. entrySet()は下線付きで "pairs.getValue()"にキャストを追加しました。私はそれを実行することによって例外が発生します:S – ZelelB

+0

ああ、おそらくあなたはマップにキャストする必要があります。 –

+0

私はそれをしなかったが、例外.. – ZelelB

2

次の2つのキーと値を含むMap.Entry要素を取得したい場合は、それは本当に多くなりますより自然なクラスPair<String, String>を作成して、1つの要素の2つのキーを結合し、1つのマップのキーとして使用しますネストマップではなく

あなたがこれを行う場合は、あなたの主な構造はMap<Pair<String, String>, String>なり、Map.entrySet()メソッドを使用すると、あなたがあなたが後にしているものを約与えイテレータを取得することができ、そこからSet<Map.Entry<String, String>, String>を与えるだろう。

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

編集注:

上記Pairクラスは、基本的にMap.Entryと同じであるので、あなたはMap<Map.Entry<String, String>, String>を構築することにより、キーの新しいクラスを作成しないようにできます。私はそれがコードを少し明確にしないと思うが、それは確かに機能的に同等にされることができる。

サンプルコード以下のコードで

、私は(実際の使用のために、あなたは独立したクラスとして抽出したい場合があります)内部staticとして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()方法は不可能または不自然かもしれない。

一方、あなたの要件(同じ他の応答に関するコメントに記載されている)は、グアバのTableで提供されているものとかなり似ています。それはオープンソースであり、それを見るとあなたにアイデアを与えるかもしれません。あなたはdownload the source for guava hereです。

具体的には、グアバの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(); 
     } 
    } 
    } 

それはグアバで他のものに依存してあなただけにこのコードをコピーすることはできませんが、それは基本を示していあなたがしなければならないことのパターン。

+0

しかし、私は何も印刷したくありません。マップ全体のイテレータを取得したい、後でStringMap2Dクラスのイテレータとして使用できます。 iteratorは 'stringmap.iterator();'と似ています。なぜなら、私のマップは2Dのディメンションマップなので、1番目のマップの値としてネストされたマップがあります。 – ZelelB

+0

印刷について言及しましたか?私は今は持っていますが、イテレータを使用するデモとしてコード内でのみ使用されています。 –

+0

質問Robyを編集しました。どうぞご覧ください。ありがとう! – ZelelB

関連する問題