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