Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Java 8, what is the most concise way of creating a sorted AND grouped list of Strings

Using Java 8, what is the most concise way of creating a sorted AND grouped list of Strings? Show the old way and the new way using Lambdas and the Collections and Streams framework.

You can show using 3rd party libraries (popular ones) for the old (or new) way.

However, I suggest that vanilla Java be used because that shows the changes that the language changes in Java 8 bring to the table for the task.

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

It will be sorted and grouped such that ...

Given this list: "Beer", "Apple", "Banana", "Ananas", "Mango", "Blue Berry"

A Map will produced containing the first letter as the key. The values in the map will be a sorted List of all the words beginning with that key (letter):

  • key: A values: ["Ananas","Apple"]
  • key: B values: ["Banana","Beer","Blue Berry"]
  • key: M values: ["Mango"]
like image 958
The Coordinator Avatar asked Oct 28 '13 12:10

The Coordinator


People also ask

How do I sort a list in Java 8?

There are multiple ways to sort a list in Java 8, for example, you can get a stream from the List and then use the sorted() method of Stream class to sort a list like ArrayList, LinkedList, or Vector and then convert back it to List. Alternatively, you can use the Collections. sort() method to sort the list.

What is the use of groupingBy in Java 8?

groupingBy() method in Java 8 now permits developers to perform GROUP BY operation directly. GROUP BY is a SQL aggregate operation that is quite useful. It enables you to categorise records based on specified criteria.


2 Answers

Using Java, with no help from 3rd party libraries, there is the old way and the new way. Just sorting used to be easy with Collections.sort(..).

The challenge with the old way was that a lot of code was required to group the values.

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

Old 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); 

New 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);

New Java 8 with source data already as a 'Stream'

As suggested by @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);
like image 175
The Coordinator Avatar answered Oct 21 '22 14:10

The Coordinator


With the popular third-party Guava library, compatible with Java 6:

TreeMultimap<Character, String> multimap = TreeMultimap.create();
for (String string : list) {
  multimap.put(string.charAt(0), string);
}
return Multimaps.asMap(ImmutableListMultimap.copyOf(multimap));

This does deduplicate strings, so an alternate version that allows duplicate strings:

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());
like image 24
Louis Wasserman Avatar answered Oct 21 '22 14:10

Louis Wasserman