使用Java 8,创建一个按字母顺序排序并分组的字符串列表的最简洁方法是什么?

13

使用Java 8,创建一个排序和分组的字符串列表的最简洁方法是什么?展示使用Lambda和Collections和Streams框架的旧方法和新方法。

您可以展示使用第三方库(流行的库)来实现旧(或新)方法。

然而,我建议使用原始的Java代码,因为这可以展示Java 8语言变化对任务所带来的改变。

Input: List<String>
Output: Map<Character<List<String>>
The key of map is 'A' to 'Z'
Each list in the map are sorted.

将给定的列表:"Beer","Apple","Banana","Ananas","Mango","Blue Berry" 进行排序和分组,使得结果为一个Map。这个Map以每个单词的首字母作为键(key),而对应的值(values)则是以这个字母开头的单词的排序后的List

  • 键(key)为 A,对应的值(values)为 ["Ananas", "Apple"]
  • 键(key)为 B,对应的值(values)为 ["Banana", "Beer", "Blue Berry"]
  • 键(key)为 M,对应的值(values)为 ["Mango"]

2
“排序和分组”是什么意思?你是如何对它们进行分组的?(并且“旧方法”是否允许使用第三方库?) - Louis Wasserman
2个回答

31

在Java中,没有使用第三方库,有一种旧的方法和新的方法。以前只需要使用Collections.sort(..)就可以轻松排序。

旧方法的挑战在于需要大量代码来分组值。

 - Input: List<String>
 - Output: Map<Character,<List<String>>
 - The key of map is 'A' to 'Z'
 - Each list in the map are sorted.

旧版Java

List<String> keywords = Arrays.asList("Apple", "Ananas", "Mango", "Banana", "Beer"); 
Map<Character, List<String>> result = new HashMap<Character, List<String>>(); 
for(String k : keywords) {   
    char firstChar = k.charAt(0);     
    if(!result.containsKey(firstChar)) {     
        result.put(firstChar, new  ArrayList<String>());   
    }     
    result.get(firstChar).add(k); 
} 
for(List<String> list : result.values()) {   
    Collections.sort(list); 
}
System.out.println(result); 

全新的Java 8

List<String> keywords = Arrays.asList("Apple", "Ananas", "Mango", "Banana", "Beer");

Map<Character, List<String>> result = keywords.stream()
     .sorted()
     .collect(Collectors.groupingBy(it -> it.charAt(0)));

System.out.println(result);

新的Java 8版本已经将源数据作为“流”进行处理

如@KevinO所建议的那样

 Map<Character, List<String>> result = Stream
      .of( "Apple", "Ananas", "Mango", "Banana","Beer")
      .sorted()
      .collect(Collectors.groupingBy(it -> it.charAt(0)))

System.out.println(result);

只是一点提示:如果列表用作流,则可以替换为Stream.of() - KevinO
@KevinO 也许你可以详细说明一下。为了让大家清楚明白你的方法,为什么不发表一份替代性答案呢? - The Coordinator
这并不是一个新的答案,只是一个可能会派上用场的替代方案。你的Java 8示例代码如下:Map<Character, List<String>> result = Stream.of("Apple", "Ananas", "Mango", "Banana", "Beer").sorted().collect(Collectors.groupingBy(it -> it.charAt(0))) - KevinO
1
@KevinO 我明白了,解释得很好。我想展示的是转换过程中发生的事情,而不是源是什么,无论是流还是列表或集合或可迭代对象等等。如果用户已经有一个流,他们就不需要先调用 .stream() 方法。我们中的一些人仍然使用列表,你知道的!许多数据仍然以列表的形式出现。但我会整合你的建议。谢谢! - The Coordinator

6
使用流行的第三方库Guava,与Java 6兼容:
TreeMultimap<Character, String> multimap = TreeMultimap.create();
for (String string : list) {
  multimap.put(string.charAt(0), string);
}
return Multimaps.asMap(ImmutableListMultimap.copyOf(multimap));

这段代码可以去重字符串,如果想要允许重复的字符串,则可以使用以下版本:
ImmutableListMultimap.Builder<Character, String> builder = 
  ImmutableListMultimap.builder();
for (String string : Ordering.natural().sortedCopy(list)) {
  builder.put(string.charAt(0), string);
}
return Multimaps.asMap(builder.build());

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