在HashMap中添加List的快捷方式

Dam*_*amo 52 java collections hashmap

我经常需要获取对象列表,并根据对象中包含的值将它们分组到Map中.例如.按国家/地区列出用户和组.

我的代码通常如下所示:

Map<String, List<User>> usersByCountry = new HashMap<String, List<User>>();
for(User user : listOfUsers) {
    if(usersByCountry.containsKey(user.getCountry())) {
        //Add to existing list
        usersByCountry.get(user.getCountry()).add(user);

    } else {
        //Create new list
        List<User> users = new ArrayList<User>(1);
        users.add(user);
        usersByCountry.put(user.getCountry(), users);
    }
}
Run Code Online (Sandbox Code Playgroud)

但是我不禁想到这很尴尬,而且一些大师有更好的方法.到目前为止,我能看到的最接近的是来自Google CollectionsMultiMap.

有没有标准方法?

谢谢!

Bal*_*usC 71

在Java 8中,您可以使用Map#computeIfAbsent().

Map<String, List<User>> usersByCountry = new HashMap<>();

for (User user : listOfUsers) {
    usersByCountry.computeIfAbsent(user.getCountry(), k -> new ArrayList<>()).add(user);
}
Run Code Online (Sandbox Code Playgroud)

或者,使用Stream API 来直接Collectors#groupingBy()转到:ListMap

Map<String, List<User>> usersByCountry = listOfUsers.stream().collect(Collectors.groupingBy(User::getCountry));
Run Code Online (Sandbox Code Playgroud)

在Java 7或更低版​​本中,您可以获得的最佳结果如下:

Map<String, List<User>> usersByCountry = new HashMap<>();

for (User user : listOfUsers) {
    List<User> users = usersByCountry.get(user.getCountry());
    if (users == null) {
        users = new ArrayList<>();
        usersByCountry.put(user.getCountry(), users);
    }
    users.add(user);
}
Run Code Online (Sandbox Code Playgroud)

Commons Collections有一个LazyMap,但它没有参数化.番石榴没有一种LazyMap或者LazyList,但你可以使用Multimap它,如下面的多基因润滑剂的回答所示.

  • 我知道这无关紧要,但也许新手需要知道映射函数将获取密钥作为参数,因此最好使用 'k' 而不是 'v' `usersByCountry.computeIfAbsent(user.getCountry() , k -&gt; new ArrayList&lt;&gt;()).add(user);` (2认同)

pol*_*nts 20

Guava Multimap确实是最合适的数据结构,实际上,有一种Multimaps.index(Iterable<V>, Function<? super V,K>)实用方法可以完全按照你想要的方式执行:获取Iterable<V>(a List<V>是),并应用它Function<? super V, K>来获取密钥Multimap<K,V>.

以下是文档中的示例:

例如,

  List<String> badGuys
      = Arrays.asList("Inky", "Blinky", "Pinky", "Pinky", "Clyde");
  Function<String, Integer> stringLengthFunction = ...;
  Multimap<Integer, String> index
      = Multimaps.index(badGuys, stringLengthFunction);
  System.out.println(index);
Run Code Online (Sandbox Code Playgroud)

版画

 {4=[Inky], 5=[Pinky, Pinky, Clyde], 6=[Blinky]}
Run Code Online (Sandbox Code Playgroud)

在你的情况下,你会写一个Function<User,String> userCountryFunction = ....

  • +1令我感到沮丧的是,编写比这更多的代码的答案排名更高,只是因为他们是最快的进来.:( (2认同)
  • @Kevin:我希望你最终会停下来=)顺便说一句,我计划最终在各种Guava类上编写关于stackoverflow的Q/A文章,以展示它的功能. (2认同)
  • 我每天只停留一两次,从而保证我没有机会得到我的答案.<叹气>我认为你的想法很棒.我认为你的意思是发一个问题并自己回答.你会得到一些人告诉你这里有一些不道德的事情,但是它被更广泛的SO社区明确批准,因为他们的目标是让SO拥有很好的内容. (2认同)