Java 如何优雅地交换 Map 中的键和值

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4436999/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 17:29:26  来源:igfitidea点击:

How to swap keys and values in a Map elegantly

javacollectionshashmap

提问by kostja

I already know how to do it the hard way and got it working - iterating over entries and swapping "manually". But i wonder if, like so many tasks, this one can be solved in a more elegant way.

我已经知道如何以艰难的方式做到这一点并让它工作 - 迭代条目并“手动”交换。但我想知道,像许多任务一样,是否可以以更优雅的方式解决这个问题。

I have read this post, unfortunately it does not feature elegant solutions. I also have no possibility to use any fancy Guava BiMaps or anything outside the jdk (project stack is already defined).

我读过这篇文章,不幸的是它没有提供优雅的解决方案。我也无法使用任何花哨的 Guava BiMaps 或 jdk 之外的任何东西(项目堆栈已经定义)。

I can assume that my map is bijective, btw :)

我可以假设我的地图是双射的,顺便说一句:)

采纳答案by Aaron Digulla

The standard API / Java runtime doesn't offer a bi-directional map, so the only solution is to iterate over all entries and swap them manually.

标准 API / Java 运行时不提供双向映射,因此唯一的解决方案是迭代所有条目并手动交换它们。

What you can do is create a wrapper class which contains two maps and which does a dual put()internally so you have fast two views on the data.

您可以做的是创建一个包装类,其中包含两个地图并在put()内部执行双重操作,因此您可以快速查看数据的两个视图。

[EDIT] Also, thanks to open source, you don't have to include a third party library, you can simply copy the classes you need into your own project.

[编辑] 另外,由于开源,您不必包含第三方库,您只需将所需的类复制到您自己的项目中即可。

回答by slezica

Maps are not like lists, which can be reversed by swapping head with tail.

映射不像列表,可以通过交换头部和尾部来反转列表。

Objects in maps have a computed position, and using the value as key and the key as value would requiere to re-compute the storage place, essentialy building another map. There is no elegant way.

地图中的对象有一个计算位置,使用值作为键和键作为值将需要重新计算存储位置,本质上是构建另一个地图。没有优雅的方式。

There are, however, bidirectional maps. Those may suit your needs. I'd reconsider using third-party libraries.

但是,存在双向映射。这些可能适合您的需求。我会重新考虑使用第三方库。

回答by Fortyrunner

There are some jobs that can be simplified to a certain point and no more. This may be one of them!

有些工作可以简化到一定程度,仅此而已。这可能就是其中之一!

If you want to do the job using Java collections apis only then brute force is the way to go - it will be quick (unless the collection is huge) and it will be an obvious piece of code.

如果您只想使用 Java 集合 api 来完成这项工作,那么暴力是可行的方法 - 它会很快(除非集合很大)并且它将是一段明显的代码。

回答by Eyal Schneider

If you don't have a choice to use a third party library, I don't consider the following code so ugly (though some scripting languages do have elegant ways of doing it):

如果您没有选择使用第三方库,我不认为以下代码如此丑陋(尽管某些脚本语言确实有优雅的方法):

//map must be a bijection in order for this to work properly
public static <K,V> HashMap<V,K> reverse(Map<K,V> map) {
    HashMap<V,K> rev = new HashMap<V, K>();
    for(Map.Entry<K,V> entry : map.entrySet())
        rev.put(entry.getValue(), entry.getKey());
    return rev;
}

回答by Nikita Marshalkin

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

回答by User8461

As a hint to answer https://stackoverflow.com/a/42091477/8594421

作为回答https://stackoverflow.com/a/42091477/8594421的提示

This only works, if the map is not a HashMap and does not contain duplicate values.

这仅适用于映射不是 HashMap 且不包含重复值的情况。

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

throws an exception

抛出异常

java.lang.IllegalStateException: Duplicate key

java.lang.IllegalStateException:重复键

if there are values more than once.

如果值不止一次。

The solution:

解决方案:

HashMap<String,String> newMap = new HashMap<>();

for(Map.Entry<String,String> entry : oldMap.entrySet())
        newMap.put(entry.getValue(), entry.getKey());

// Add inverse to old one
oldMap.putAll(newMap);

回答by kebin

If you had access to apache commons-collections, you could have used MapUtils.invertMap.

如果您可以访问 apache commons-collections,则可以使用MapUtils.invertMap

Note: The behaviour in case of duplicated values is undefined.

注意:重复值的行为是未定义的。

(Replying to this as this is the first google result for "java invert map").

(回复这个因为这是“java invert map”的第一个谷歌结果)。

回答by RAJA SEKHAR

This will work for duplicate values in the map also, but not for HashMapas values.

这也适用于地图中的重复值,但不适用于HashMap作为值。

package Sample;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class Sample {
    public static void main(String[] args) { 
        Map<String,String> map = new HashMap<String,String>(); 
        Map<String, Set<String> > newmap = new HashMap<String, Set<String> >(); 

        map.put("1", "a"); 
        map.put("2", "a"); 
        map.put("3", "b"); 
        map.put("4", "b"); 
        System.out.println("before Reversing \n"+map.toString()); 

        for (Map.Entry<String, String> entry : map.entrySet()) 
        { 
            String oldVal = entry.getValue(); 
            String oldKey = entry.getKey(); 
            Set<String> newVal = null; 

            if (newmap.containsKey(oldVal)) 
            { 
                newVal = newmap.get(oldVal); 
                newVal.add(oldKey); 
            } 
            else 
            { 
                newVal= new HashSet<>(); 
                newVal.add(oldKey); 
            } 
            newmap.put(oldVal, newVal); 
        } 
        System.out.println("After Reversing \n "+newmap.toString()); 
    } 
}