Best practice to convert List to a Map. In other words how to apply grouping on a List or Collection without writing separate methods for each.
// Original list List<Person> // Expected group Map<String, List<Person>>
private static Map<String, List<Person>> groupBySalary(List<Person> persons) { Map<String, List<Person>> groupedMap = new HashMap<String, List<Person>>(); for (Person p : persons) { // Grouping criteria String role = p.getRole(); List<Person> list = groupedMap.get(role); if (list == null) { // not exist in group. create and add for first time. list = new ArrayList<Person>(); groupedMap.put(role, list); } list.add(p); } return groupedMap; }
Later if we want to group it by Role or First name or maybe some thing different; then the Declaration remains the same but we need to write different methods. This is not a nice practice to duplicate the code. See the class ListToMapHelper which demonstrate how a list can be grouped easily to Map by providing the grouping criteria on the fly. Something like you provide the Sorting criteria for Collections class. In same way you provide the Grouping criteria to this Helper static method. With lambda expressions in Java 8 this is again must simpler with just one line code. See main method for usage.
package in.mbm.playground; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; /** * * @author Mohammed Bin Mahmood * */ public class ListToMapHelper { public interface IGroupingCriteria<G, T> { /** * Takes a Type T from which Grouping has to be done. check main method for the usage. * * @param type T * @return Object of type G which is the grouping criteria. */ public G group(T type); }; /** * Takes an Iterable and Grouping criteria implementation and returns a Map grouped by the * criteria. * * @param iteratableCollection * @param groupBy * @return */ public static <G, T> Map<G, List<T>> groupBy(Iterable<T> iteratableCollection, IGroupingCriteria<G, T> groupBy) { Map<G, List<T>> map = new HashMap<G, List<T>>(); for (T type : iteratableCollection) { // grouping criteria G group = groupBy.group(type); List<T> list = map.get(group); if (list == null) { // not exist in group. create and add for first time. list = new ArrayList<T>(); map.put(group, list); } list.add(type); } return map; } public static void main(String[] args) { // assume list of persons is populated List<Person> persons = fillSomePersons(); // group persons by Role. // provide the implementation of IGroupingCriteria with String as Key and Person as the Type // itself Map<String, List<Person>> map = groupBy(persons, new IGroupingCriteria<String, Person>() { @Override public String group(Person p) { // group by role. return p.getRole(); } }); // by Java 8 map = groupBy(persons, p -> p.getRole()); // print and see the results. for (Entry<String, List<Person>> entry : map.entrySet()) { System.out.println(entry.getKey() + "\t" + entry.getValue()); } } private static class Person { private final int id; private String name, role; Person(int id) { this.id = id; } Person setName(String name) { this.name = name; return this; } String getRole() { return role; } Person setRole(String role) { this.role = role; return this; } @Override public String toString() { return id + " " + name + " " + role; } } private static List<Person> fillSomePersons() { List<Person> persons = new ArrayList<ListToMapHelper.Person>(5); persons.add(new Person(1).setName("Person A").setRole("Role A")); persons.add(new Person(2).setName("Person B").setRole("Role A")); persons.add(new Person(3).setName("Person C").setRole("Role B")); persons.add(new Person(4).setName("Person D").setRole("Role B")); persons.add(new Person(5).setName("Person E").setRole("Role A")); persons.add(new Person(6).setName("Person F").setRole("Role A")); persons.add(new Person(7).setName("Person G").setRole("Role B")); persons.add(new Person(8).setName("Person H").setRole("Role C")); persons.add(new Person(9).setName("Person I").setRole("Role A")); return persons; } private static Map<String, List<Person>> groupByRole(List<Person> persons) { Map<String, List<Person>> groupedMap = new HashMap<String, List<Person>>(); for (Person p : persons) { // Grouping criteria String role = p.getRole(); List<Person> list = groupedMap.get(role); if (list == null) { // not exist in group. create and add for first time. list = new ArrayList<Person>(); groupedMap.put(role, list); } list.add(p); } return groupedMap; } }
Hope this example helps. Do share your feedback and pass it on.