I query the DB for two columns where the first one is the key to the second one. How can I convert the resulting list to a single map? Is it even possible? I have just seen examples with beans.
List<Map<String, Object>> steps = jdbcTemplate.queryForList( "SELECT key, value FROM table"); // well this doesn't work Map<String, String> result = steps.stream() .collect(Collectors.toMap(s -> s.get("key"), s -> s.get("value"))); 4 Answers
You forgot to convert your key and value mappings to produce String:
final Map<String, String> result = steps .stream() .collect(Collectors.toMap(s -> (String) s.get("key"), s -> (String) s.get("value"))); Full example
public static void main(String[] args) { final List<Map<String, Object>> steps = queryForList("SELECT key, value FROM table"); final Map<String, String> result = steps .stream() .collect(Collectors.toMap(s -> (String) s.get("key"), s -> (String) s.get("value"))); result.entrySet().forEach(e -> System.out.println(e.getKey() + " -> " + e.getValue())); } private static List<Map<String, Object>> queryForList(String s) { final List<Map<String, Object>> result = new ArrayList<>(); for (int i = 0; i < 10; i++) { final Map<String, Object> map = new HashMap<>(); map.put("key", "key" + i); map.put("value", "value" + i); result.add(map); } return result; } Which prints
key1 -> value1 key2 -> value2 key0 -> value0 key5 -> value5 key6 -> value6 key3 -> value3 key4 -> value4 key9 -> value9 key7 -> value7 key8 -> value8 7We can use the reduce() of java streams to convert a list of maps to a single map in java.
Please check the following code on how it is used.
For example:
@Data @AllArgsConstructor public class Employee { private String employeeId; private String employeeName; private Map<String,Object> employeeMap; } public class Test{ public static void main(String[] args) { Map<String, Object> map1 = new HashMap<>(); Map<String, Object> map2 = new HashMap<>(); Map<String, Object> map3 = new HashMap<>(); map1.put("salary", 1000); Employee e1 = new Employee("e1", "employee1", map1); map2.put("department", "HR"); Employee e2 = new Employee("e2", "employee2", map2); map3.put("leave balance", 14); Employee e3 = new Employee("e3", "employee3", map3); //now we create a employees list and add the employees e1,e2 and e3. List<Employee> employeeList = Arrays.asList(e1,e2,e3); //now we retreive employeeMap from all employee objects and therefore have a List of employee maps. List<Map<String, Object>> employeeMaps = employeeList .stream() .map(Employee::getEmployeeMap) .collect(Collectors.toList()); System.out.println("List of employee maps: " + employeeMaps); // to reduce a list of maps to a single map, we use the reduce function of stream. Map<String, Object> finalMap = employeeMaps .stream() .reduce((firstMap, secondMap) -> { firstMap.putAll(secondMap); return firstMap; }).orElse(null); System.out.println("final Map: "+ finalMap); } } Output: List of employee maps: [{salary=1000}, {department=HR}, {leave balance=14}].
final Map: {salary=1000, department=HR, leave balance=14}
PS: Apologies for the extended answer, this is my first time in stackoverflow. Thank you :-)
Adding on to what esin88 said above, if there is a possibility that we get duplicate keys in the list of maps, we would like to get a map with key and list of values rather than key value pair which can be done like below.
public static void main(String[] args) { final List<Map<String, Object>> steps = queryForList("SELECT key, value FROM table"); /*final Map<String, String> result = steps.stream() .collect(Collectors.toMap(s -> (String) s.get("key"), s -> (String) s.get("value")));*/ final Map<String, List<String>> result1 = steps.stream() .collect(Collectors.groupingBy(k -> String.valueOf(k.get("key")), Collectors.mapping(l -> String.valueOf(l.get("value")), Collectors.toList()))); result1.entrySet().forEach(e -> System.out.println(e.getKey() + " -> " + e.getValue())); } private static List<Map<String, Object>> queryForList(String s) { final List<Map<String, Object>> result = new ArrayList<>(); Map<String, Object> map = new HashMap<>(); for (int i = 0; i < 10; i++) { map = new HashMap<>(); map.put("key", "key" + i); map.put("value", "value" + i); result.add(map); } map = new HashMap<>(); map.put("key", "key1"); map.put("value", "value20"); result.add(map); return result; } The result would look like
key1 -> [value1, value20] key2 -> [value2] key0 -> [value0] key5 -> [value5] key6 -> [value6] key3 -> [value3] key4 -> [value4] key9 -> [value9] key7 -> [value7] key8 -> [value8] The problem is you have a list of maps. The code below should work:
Map<String, String> result = new HashMap<>(); steps.stream().forEach(map -> { result.putAll(map.entrySet().stream() .collect(Collectors.toMap(entry -> entry.getKey(), entry -> (String) entry.getValue()))); }); If we try to run this example
Map<String, Object> steps1 = new HashMap<>(); steps1.put("key11", "value11"); steps1.put("key12", "value12"); Map<String, Object> steps2 = new HashMap<>(); steps2.put("key21", "value21"); steps2.put("key22", "value22"); List<Map<String, Object>> steps = new ArrayList<>(); steps.add(steps1); steps.add(steps2); Map<String, String> result = new HashMap<>(); steps.stream().forEach(map -> { result.putAll(map.entrySet().stream() .collect(Collectors.toMap(entry -> entry.getKey(), entry -> (String) entry.getValue()))); }); System.out.println(result); It happily gives us the output like that:
{key12=value12, key11=value11, key22=value22, key21=value21} 3