如何使用值作为列表或数组来分组HashMap的键

4

我创建了一个使用字符串作为键和整数作为值的Map。因此,它就像是citiesWithCodes

目前为了测试目的,我手动将这些值放入HashMap中。它们是:

Map<String, Integer> citiesWithCodes = new HashMap<String, Integer>();
        citiesWithCodes.put("Berlin", 49);
        citiesWithCodes.put("Frankfurt", 49);
        citiesWithCodes.put("Hamburg", 49);
        citiesWithCodes.put("Cologne", 49);
        citiesWithCodes.put("Salzburg", 43);
        citiesWithCodes.put("Vienna", 43);
        citiesWithCodes.put("Zurich", 41);
        citiesWithCodes.put("Bern", 41);
        citiesWithCodes.put("Interlaken", 41);

我希望能够根据城市代码以列表或数组的形式获取城市。例如,对于值43,应该返回类似于{43=[维也纳,萨尔茨堡]}的结果。

我尝试了以下方法。这是一种不太优雅的方法,而且并没有给出正确的结果。

   public static Map<Integer, List<String>> codeCities(Map<String, Integer> citiesWithCodes){
       Map<Integer, List<String>> segList = new HashMap<Integer, List<String>>();
       List<String> city;
       Iterator<Entry<String, Integer>> i = citiesWithCodes.entrySet().iterator();
       while (i.hasNext()) {
           city = new ArrayList<String>();
           Entry<String, Integer> next = i.next();
           i.remove();
           city.add(next.getKey());
           for (Entry<String, Integer> e : citiesWithCodes.entrySet()) {
               if(e.getValue().equals(next.getValue())){
                   city.add(e.getKey());
                   citiesWithCodes.remove(e);
               }
           }
           System.out.println(city);
           segList.put(next.getValue(), city);
       }
       return segList;
   }

我得到的输出是:{49=[科隆], 41=[因特拉肯], 43=[萨尔茨堡]}。请问有人能告诉我正确的方法来实现这个结果吗?
注:我知道可以使用MultiMap来实现,但我们只能使用Java Collection Framework而不能使用Java 8。

你能用Java 8来做这个吗? - Schidu Luca
@SchiduLuca。不幸的是,该项目的范围仅限于Java 7。 - Procrastinator
3个回答

8

Java 8之前

package com.stackoverflow;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

public class HashMapToListMap {

public static void main(String[] args) {
    Map<String, Integer> citiesWithCodes = new HashMap<String, Integer>();
    citiesWithCodes.put("Berlin", 49);
    citiesWithCodes.put("Frankfurt", 49);
    citiesWithCodes.put("Hamburg", 49);
    citiesWithCodes.put("Cologne", 49);
    citiesWithCodes.put("Salzburg", 43);
    citiesWithCodes.put("Vienna", 43);
    citiesWithCodes.put("Zurich", 41);
    citiesWithCodes.put("Bern", 41);
    citiesWithCodes.put("Interlaken", 41);

    Map<Integer, List<String>> result = new HashMap<Integer, List<String>>();
    for(Entry<String,Integer> entry : citiesWithCodes.entrySet()){
            List<String> list = new ArrayList<String>();
            if(result.containsKey(entry.getValue()))
                list = result.get(entry.getValue());
            list.add(entry.getKey());
            result.put(entry.getValue(), list);
    }
    System.out.println(result);
}

Java 8之后

 package com.stackoverflow;

 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;

public class HashMapToListMap {

public static void main(String[] args) {
    Map<String, Integer> citiesWithCodes = new HashMap<String, Integer>();
    citiesWithCodes.put("Berlin", 49);
    citiesWithCodes.put("Frankfurt", 49);
    citiesWithCodes.put("Hamburg", 49);
    citiesWithCodes.put("Cologne", 49);
    citiesWithCodes.put("Salzburg", 43);
    citiesWithCodes.put("Vienna", 43);
    citiesWithCodes.put("Zurich", 41);
    citiesWithCodes.put("Bern", 41);
    citiesWithCodes.put("Interlaken", 41);


    Map<Integer, List<String>> result =  citiesWithCodes.entrySet().stream().collect(Collectors.groupingBy(
            Map.Entry::getValue,Collectors.mapping(Map.Entry::getKey, Collectors.toList())));
    System.out.println(result);
}

}

4

如果你的范围仅限于Java 7,那么尝试按以下代码进行更改:

 Map<Integer, List<String>> segList = new HashMap<Integer, List<String>>();
 Iterator<Entry<String, Integer>> i = citiesWithCodes.entrySet().iterator();
            while (i.hasNext()) {
                  Entry<String, Integer> next = i.next();
                  if (segList.get(next.getValue()) != null) {
                       List<String> city= segList.get(next.getValue());
                       city.add(next.getKey());
                       segList.put(next.getValue(), city);
                  }else{
                        List<String> city=new ArrayList<String>();
                        city.add(next.getKey());
                        segList.put(next.getValue(), city);

                  }
            }

输出:

{49=[法兰克福,柏林,汉堡,科隆],41=[伯尔尼,苏黎世, 因特拉肯],43=[维也纳,萨尔茨堡]}


0
您总是构造一个新的 List<String> 来保存具有给定键的城市列表。这发生在该行中。
city = new ArrayList<String>();

请将此替换为

if(segList.containsKey(next.getValue())) {
    city = segList.get(next.getValue());
} else {
    city = new ArrayList<String>();
}

代码应该按预期工作。

编辑:@eran 更快,但我将其保留,因为它解释了较不优雅和过时的方法中出现的错误。


我需要在for循环之前将值添加到city中。因此,我不能仅在else部分初始化它。 - Procrastinator
此时与原始代码没有区别,只需用我的五行代码替换你的一行。 - blafasel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接