如果您想获取包含两个键和值的元素,那么创建一个将两个键组合在一个元素中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();
}
}
}
您不能只复制此代码,因为它依赖于番石榴中的其他内容,但它显示了您必须做的基本模式。