假设我有一个带字符串键和整数值的HashMap:
map = {cat=1, kid=3, girl=3, adult=2, human=5, dog=2, boy=2}
我想通过将此信息放入另一个HashMap来切换键和值。我知道HashMap不能有重复的键,因此我尝试将信息放入带有Integer的HashMap中,用于映射到String ArrayList的键,以便我可以将一个Integer映射到多个字符串:
swap = {1=[cat], 2=[adult, dog, boy], 3=[kid, girl], 5=[human]}
我尝试了以下代码:
HashMap<Integer, ArrayList<String>> swap = new HashMap<Integer, ArrayList<String>>();
for (String x : map.keySet()) {
for (int i = 0; i <= 5; i++) {
ArrayList<String> list = new ArrayList<String>();
if (i == map.get(x)) {
list.add(x);
swap.put(i, list);
}
}
}
我的代码唯一的区别是我没有将数字5硬编码到我的索引中;我有一个方法,在原始的HashMap中找到最高的整数值并使用它。我知道它工作正常,因为我得到相同的输出,即使我在那里硬编码5,我只是没有包括它来节省空间。
我的目标是能够使用任何数据集进行“反转”,否则我只能对值进行硬编码。我从上面的代码得到的输出是:
swap = {1=[cat], 2=[boy], 3=[girl], 5=[human]}
正如您所看到的,我的问题是值ArrayList只保留放入其中的最后一个String,而不是收集所有String。如何使ArrayList存储每个String,而不仅仅是最后一个String?
答案 0 :(得分:22)
使用Java 8,您可以执行以下操作:
Map<String, Integer> map = new HashMap<>();
map.put("cat", 1);
map.put("kid", 3);
map.put("girl", 3);
map.put("adult", 2);
map.put("human", 5);
map.put("dog", 2);
map.put("boy", 2);
Map<Integer, List<String>> newMap = map.keySet()
.stream()
.collect(Collectors.groupingBy(map::get));
System.out.println(newMap);
输出将是:
{1=[cat], 2=[adult, dog, boy], 3=[kid, girl], 5=[human]}
答案 1 :(得分:6)
你正在为每次迭代重新创建arrayList,我无法找到使用该逻辑的方法,这是一个很好的方法,但不需要检查最大整数:
for (Map.Entry<String, Integer> entry : map.entrySet()) {
String key = entry.getKey();
Integer value = entry.getValue();
List<String> get = swap.get(value);
if (get == null) {
get = new ArrayList<>();
swap.put(value, get);
}
get.add(key);
}
答案 2 :(得分:3)
最好的方法是迭代原始地图的键集。
此外,您必须确保列表存在于目标地图中的任何键:
for (Map.Entry<String,Integer> inputEntry : map.entrySet())
swap.computeIfAbsent(inputEntry.getValue(),()->new ArrayList<>()).add(inputEntry.getKey());
答案 3 :(得分:2)
这显然不是最好的解决方案,但是通过交换内部和外部循环来解决问题的方法与下面所示相同。
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("cat", 1);
map.put("kid", 3);
map.put("girl", 3);
map.put("adult", 2);
map.put("human", 5);
map.put("dog", 2);
map.put("boy", 2);
HashMap<Integer, ArrayList<String>> swap = new HashMap<Integer, ArrayList<String>>();
for (Integer value = 0; value <= 5; value++) {
ArrayList<String> list = new ArrayList<String>();
for (String key : map.keySet()) {
if (map.get(key) == value) {
list.add(key);
}
}
if (map.containsValue(value)) {
swap.put(value, list);
}
}
<强>输出强>
{1 = [cat],2 = [成人,狗,男孩],3 = [孩子,女孩],5 = [人类]}
答案 4 :(得分:2)
我能想到的最好方法是在现有地图上使用Map.forEach
方法,在新地图上使用Map.computeIfAbsent
方法:
Map<Integer, List<String>> swap = new HashMap<>();
map.forEach((k, v) -> swap.computeIfAbsent(v, k -> new ArrayList<>()).add(k));
作为旁注,您可以使用菱形运算符<>
来创建新映射(在调用映射的构造函数时不需要重复键和值的类型,因为编译器会推断它们)
作为第二方,最好使用接口类型而不是具体类型,包括通用参数类型和实际类型。这就是为什么我分别使用List
和Map
代替ArrayList
和HashMap
。
答案 5 :(得分:1)
在groupingBy
中使用Jacob's answer,但Map.entrySet
使用suggested by Boris以获得更好的效果,Collectors
:
// import static java.util.stream.Collectors.*
Map<Integer, List<String>> swap = map.entrySet()
.stream()
.collect(groupingBy(Entry::getValue, mapping(Entry::getKey, toList())));
这又使用了mapping
的另外两种方法:toList
和toMap
。
如果不是这两个辅助函数,解决方案可能如下所示:
Map<Integer, List<String>> swap = map.entrySet()
.stream()
.collect(
groupingBy(
Entry::getValue,
Collector.of(
ArrayList::new,
(list, e) -> {
list.add(e.getKey());
},
(left, right) -> { // only needed for parallel streams
left.addAll(right);
return left;
}
)
)
);
或者,使用extension method代替groupingBy
:
Map<Integer, List<String>> swap = map.entrySet()
.stream()
.collect(
toMap(
Entry::getValue,
(e) -> new ArrayList<>(Arrays.asList(e.getKey())),
(left, right) -> {
left.addAll(right);
return left;
}
)
);
答案 6 :(得分:0)
它接缝你覆盖将它们添加到已经褶皱的arraylist的值instrad。试试这个:
HashMap<Integer, ArrayList<String>> swapedMap = new HashMap<Integer, ArrayList<String>>();
for (String key : map.keySet()) {
Integer swappedKey = map.get(key);
ArrayList<String> a = swapedMap.get(swappedKey);
if (a == null) {
a = new ArrayList<String>();
swapedMap.put(swappedKey, a)
}
a.add(key);
}
我没时间运行它(抱歉,现在没有Java编译器),但几乎可以接受:)
答案 7 :(得分:0)
您可以在merge
的java-8中使用新的Map
方法:
Map<Integer, List<String>> newMap = new HashMap<>();
map.forEach((key, value) -> {
List<String> values = new ArrayList<>();
values.add(key);
newMap.merge(value, values, (left, right) -> {
left.addAll(right);
return left;
});
});