Java 如何优雅地交换地图中的键和值
我已经知道如何通过艰苦的方式完成它,并使它工作起来——迭代条目并“手动”交换。但我想知道,像许多任务一样,这个问题能否以更优雅的方式解决 不幸的是,我读过,它没有优雅的解决方案。我也不可能使用任何花哨的番石榴Bimap或jdk之外的任何东西(项目堆栈已经定义)Java 如何优雅地交换地图中的键和值,java,collections,hashmap,Java,Collections,Hashmap,我已经知道如何通过艰苦的方式完成它,并使它工作起来——迭代条目并“手动”交换。但我想知道,像许多任务一样,这个问题能否以更优雅的方式解决 不幸的是,我读过,它没有优雅的解决方案。我也不可能使用任何花哨的番石榴Bimap或jdk之外的任何东西(项目堆栈已经定义) 我可以假设我的映射是双射的,顺便说一句:)映射不像列表,可以通过交换头部和尾部来反转 地图中的对象有一个计算的位置,使用值作为键和键作为值需要重新计算存储位置,基本上是构建另一个地图。没有优雅的方式 然而,存在双向映射。这些可能适合你的需
我可以假设我的映射是双射的,顺便说一句:)映射不像列表,可以通过交换头部和尾部来反转 地图中的对象有一个计算的位置,使用值作为键和键作为值需要重新计算存储位置,基本上是构建另一个地图。没有优雅的方式
然而,存在双向映射。这些可能适合你的需要。我会重新考虑使用第三方库。标准API/Java运行时不提供双向映射,因此唯一的解决方案是迭代所有条目并手动交换它们 您可以做的是创建一个包装类,它包含两个映射,并在内部执行双
put()
,这样您就可以快速查看数据
[编辑]此外,由于开源,您不必包含第三方库,您只需将所需的类复制到您自己的项目中即可。有些作业可以简化到某一点,仅此而已。这可能是其中之一
如果你想使用java集合API来完成这项工作,那么蛮力就是方法——它会很快(除非集合很大),它将是一个明显的代码。
如果你没有选择使用第三方库,我不认为下面的代码如此丑陋。(尽管有些脚本语言确实有优雅的方式来实现这一点)://映射必须是双射才能正常工作
公共静态哈希映射反向(映射映射){
HashMap rev=新的HashMap();
对于(Map.Entry:Map.entrySet())
rev.put(entry.getValue(),entry.getKey());
返回版本;
}
Map Map=newhashmap();
Map swapped=Map.entrySet().stream().collect(Collectors.toMap(Map.Entry::getValue,Map.Entry::getKey));
作为回答的提示
这仅适用于映射不是HashMap且不包含重复值的情况
Map<String,String> newMap = oldMap.entrySet().stream().collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey));
Map newMap=oldMap.entrySet().stream().collect(Collectors.toMap(Map.Entry::getValue,Map.Entry::getKey));
抛出异常
java.lang.IllegalStateException:重复密钥
如果存在不止一次的值
解决方案:
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);
HashMap newMap=newhashmap();
对于(Map.Entry:oldMap.entrySet())
newMap.put(entry.getValue(),entry.getKey());
//给旧的加反
oldMap.putAll(newMap);
如果您有权访问apache commons集合,则可以使用
注:重复值情况下的行为未定义
(回答这个问题,因为这是“java反转映射”的第一个google结果。)这也适用于映射中的重复值,但不适用于
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());
}
}
包装样品;
导入java.util.HashMap;
导入java.util.HashSet;
导入java.util.Map;
导入java.util.Set;
公共类样本{
公共静态void main(字符串[]args){
Map Map=newhashmap();
Map newmap=newhashmap();
地图放置(“1”、“a”);
地图放置(“2”、“a”);
地图放置(“3”、“b”);
地图放置(“4”、“b”);
System.out.println(“反转前\n”+map.toString());
对于(Map.Entry:Map.entrySet())
{
字符串oldVal=entry.getValue();
字符串oldKey=entry.getKey();
设置newVal=null;
if(newmap.containsKey(oldVal))
{
newVal=newmap.get(oldVal);
newVal.add(oldKey);
}
其他的
{
newVal=newhashset();
newVal.add(oldKey);
}
newmap.put(oldVal,newVal);
}
System.out.println(“反转后\n”+newmap.toString());
}
}
Java stream API提供了一套很好的API,可以帮助您实现这一点
如果值是唯一的那么下面的方法就行了。当我指的是值时,我指的是地图中的V
Map Map=newhashmap();
Map swapped=Map.entrySet()
.stream()
.collect(Collectors.toMap(Map.Entry::getValue,Map.Entry::getKey));
如果值不唯一,则使用以下值:
Map<Integer, List<String>> swapped = map.entrySet()
.stream()
.collect(Collectors.groupingBy(Map.Entry::getValue, Collectors.mapping(Map.Entry::getKey, Collectors.toList())));
Map swapped=Map.entrySet()
.stream()
.collect(Collectors.groupingBy(Map.Entry::getValue,Collectors.mapping(Map.Entry::getKey,Collectors.toList());
感谢Nikita和FreyaZ。发布新的答案,因为Nikita的答案有这么多编辑队列添加额外的实用程序库并没有真正改变项目“堆栈”的方式(比如)如果可能的话,改变你正在使用的UI框架将是一个巨大的挑战。我敦促你重新考虑你对使用番石榴的反对意见。你所需要的只是一个单循环和一行代码,这是简单而简洁的。IMHO.Java不是一种函数式语言。谢谢大家,有这么多重叠和简洁的答案,你真的很难选择哪一种一个可以接受。我想我会和Aaron Digulla一起提供一个包装解决方案。很棒的解决方案。这将是使用Java 8添加流之后的最佳答案。如果原始映射中的值在多个键中的位置会怎样?交换时会丢失值&得到一个ExceptionMap swapped=map.entrySet().stream().collect(Collectors.groupingBy(Map.Entry::getValue,Collectors.mapping(Map.Entry::getKey,Collectors.toList());@FreyaZ-omg,这会让我失败一整天!
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());
}
}
Map<String, Integer> map = new HashMap<>();
Map<Integer, String> swapped = map.entrySet()
.stream()
.collect(Collectors.toMap(Map.Entry::getValue, Map.Entry::getKey));
Map<Integer, List<String>> swapped = map.entrySet()
.stream()
.collect(Collectors.groupingBy(Map.Entry::getValue, Collectors.mapping(Map.Entry::getKey, Collectors.toList())));