在Java中反向HashMap键和值


71

这是一个简单的问题,我有一个简单的HashMap,我想将其反转键和值。

HashMap<Character, String> myHashMap = new HashMap<Character, String>();
myHashMap.put('a', "test one");
myHashMap.put('b', "test two");

我想创建一个新的HashMap,在其中放置相反的内容。

HashMap<String, Character> reversedHashMap = new HashMap<String, Character>();
e.g. Keys "test one" & "test two" and values 'a' & 'b'.

简单的问题,简单的答案。你能告诉我们你卡在哪里吗?
Jeroen Vannevel 2013年

2
首先,您必须确保自己的价值观是唯一的。否则,应该是Map<String, List<Character>>
Alexis C.

好吧,我是JAVA的新手,不知道从哪里开始...
肯(Ken)

它们都是独一无二的,是的
Ken

2
不丢失数据并非总是可以做到的。想象一下,您有一个:->测试一个;b->测试两个;c->测试一个(在您的第一个地图中)。您将在第二张(输出)地图中得到什么?像这样:测试一个-> a(或c);测试两个-> b。所以,第一个地图有3项,第2地图刚刚2
peter.petrov

Answers:


127

它们都是独一无二的,是的

如果您确定自己的值是唯一的,则可以遍历旧地图的条目。

Map<String, Character> myNewHashMap = new HashMap<>();
for(Map.Entry<Character, String> entry : myHashMap.entrySet()){
    myNewHashMap.put(entry.getValue(), entry.getKey());
}

另外,您可以使用Guava提供的双向地图,并使用inverse()方法:

BiMap<Character, String> myBiMap = HashBiMap.create();
myBiMap.put('a', "test one");
myBiMap.put('b', "test two");

BiMap<String, Character> myBiMapInversed = myBiMap.inverse();

出来了,你也可以这样:

Map<String, Integer> map = new HashMap<>();
map.put("a",1);
map.put("b",2);

Map<Integer, String> mapInversed = 
    map.entrySet()
       .stream()
       .collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey))

最后,我对质子包装库做出了贡献,该包含Stream API的实用程序方法。这样,您可以这样做:

Map<Character, String> mapInversed = MapStream.of(map).inverseMapping().collect();

2
感谢您解释双向地图的用法。我不知道,这对我真的有用!
2014年

当我使用你的java-8方法与收藏家,我得到以下错误的Map.Entry::getValuegetKeyNon-static method cannot be referenced from a static context

1
1月,这是因为您的地图与使用mapInversed变量声明的泛型类型不同。
Marcin

如果值重复怎么办?您如何处理?
Chaitanya Uttarwar

@ChaitanyaUttarwar您必须找到一种合并策略,以映射与原始地图中与同一值相关联的不同键(您可以将它们分组到列表中,将它们求和,仅取一个键取决于您要实现的目标) )。
Alexis C.

21

Apache Commons Collections库提供了一种用于反转地图的实用方法。如果您确定myHashMap的值是唯一的,则可以使用此方法

org.apache.commons.collections.MapUtils.invertMap(java.util.Map map)

样例代码

HashMap<String, Character> reversedHashMap = MapUtils.invertMap(myHashMap) 

15

如果值不是唯一的,则反转映射的安全方法是使用Java 8的groupingBy函数

Map<String, Integer> map = new HashMap<>();
map.put("a",1);
map.put("b",2);

Map<Integer, List<String>> mapInversed = 
map.entrySet()
   .stream()
   .collect(Collectors.groupingBy(Map.Entry::getValue, Collectors.mapping(Map.Entry::getKey, Collectors.toList())))

3

我写了一个更简单的循环,也可以工作(请注意,我所有的值都是唯一的):

HashMap<Character, String> myHashMap = new HashMap<Character, String>();
HashMap<String, Character> reversedHashMap = new HashMap<String, Character>();

for (char i : myHashMap.keySet()) {
    reversedHashMap.put(myHashMap.get(i), i);
}

2

要回答有关如何实现的问题,可以从地图中获取entrySet,然后通过使用getValue askeygetKey as将其放入新地图value

但是请记住,映射中的键是唯一的,这意味着如果原始映射中的一个值带有两个不同的键,则新映射中的第二个键(按迭代顺序)将保留为值。


2

遍历键和值的列表,然后添加它们。

HashMap<String, Character> reversedHashMap = new HashMap<String, Character>();
for (String key : myHashMap.keySet()){
    reversedHashMap.put(myHashMap.get(key), key);
}

5
entrySet更好,哈希码不必每次都计算get
-A4L

@ A4L是的,但是对于简单的任务并没有太大的区别。
hichris123 2013年

2
private <A, B> Map<B, A> invertMap(Map<A, B> map) {
    Map<B, A> reverseMap = new HashMap<>();
    for (Map.Entry<A, B> entry : map.entrySet()) {
        reverseMap.put(entry.getValue(), entry.getKey());
    }
    return reverseMap;
}

重要的是要记住,put用相同的键调用时会替换该值。因此,如果您的地图具有两个具有相同值的键,则倒置地图中将只存在其中一个。


1
我认为有关如何处理重复值成为键的注释会很有用。
库珀·白金汉

@CHBuckingham同意
Mark Hetherington

1

使用下面的示例代码进行测试,并尝试使用MapUtils和Java8 Stream功能。它适用于两种情况。

public static void main(String[] args) {
    Map<String, String> test = new HashMap<String, String>();
    test.put("a", "1");
    test.put("d", "1");
    test.put("b", "2");
    test.put("c", "3");
    test.put("d", "4");
    test.put("d", "41");

    System.out.println(test);

    Map<String, String> test1 = MapUtils.invertMap(test);

    System.out.println(test1);

    Map<String, String> mapInversed = 
            test.entrySet()
               .stream()
               .collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey));

    System.out.println(mapInversed);
}

Output:
{a=1, b=2, c=3, d=41}
{1=a, 2=b, 3=c, 41=d}
{1=a, 2=b, 3=c, 41=d}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.