I have a list with a map inside and I need to turn it into a map with a list inside.
I have a List <Map <String, Object >>
and I need to change it to
Map<String, List <Object<Object>>>
.
, of course, by passing the data contained in it, matching the keys to the values
There are objects of the Date class in the Object class, this structure was used because it is the result returned by jdbcTemplate. Now I need to change that to have a date list for each unique String key.
I have a method that takes two columns from a database
and returns List<Map<String, Object >>
. One column is the username and the second column is the dates on which he was on vacation. I need a data structure that will allow me to match the key (userId
) with a list of his vacation dates.
public List<Map<String, Object>> getHoliday(String teamLeaderId) {
String query = "SELECT H.userid, date FROM Holiday H INNER JOIN Contact C on H.userid = C.UserId INNER JOIN Team T on C.TeamId = T.team_id WHERE team_leader = ? AND isApproved = 0";
return this.getJdbcTemplate().queryForList(query, teamLeaderId);
}
I'm using Java 8.
Is it possible to do?
CodePudding user response:
Plain for-loop
You can group entries having identical keys using Java 8 method computeIfAbsent()
:
List<Map<String, Object>> listOfMaps = // initilizing the list
Map<String, List<Object>> result = new HashMap<>();
for (Map<String, Object> map: listOfMaps) {
for (Map.Entry<String, Object> entry: map.entrySet()) {
result
.computeIfAbsent(entry.getKey(), k -> new ArrayList<>())
.add(entry.getValue());
}
}
If you don't feel comfortable with Java 8 features than you can replace computeIfAbsent()
with the lines shown below (note that used of computeIfAbsent()
is preferred over putIfAbsent()
because function would be evaluated lazily, meanwhile putIfAbsent()
would create a new empty List with every call):
result.putIfAbsent(entry.getKey(), new ArrayList<>());
result.get(entry.getKey()).add(entry.getValue());
Stream API
You can address this problem using Stream API:
Flatten the entries of each Map using
flatMap()
operation;Group the entries having the same key using collector
groupingBy()
and apply the combination of collectorsmapping()
andtoList()
as a downstream.
That's how it might look like:
List<Map<String, Object>> listOfMaps = // initilizing the list
Map<String, List<Object>> result = listOfMaps.stream()
.flatMap(map -> map.entrySet().stream())
.collect(Collectors.groupingBy(
Map.Entry::getKey,
Collectors.mapping(Map.Entry::getValue,
Collectors.toList())
));
CodePudding user response:
Its possible to do so using Collectors.toMap to convert the List to Map , Here a small exemple to how to do it.
package org.example;
import java.util.*;
import java.util.stream.Collectors;
public class App
{
public static void main( String[] args )
{
ArrayList<Map<String, Object >> list = new ArrayList <Map <String, Object >>(){{ // just to simulate the result
for(int i = 0; i < 10; i ){
final Integer finalI = i 1;
final Integer simulateID = (finalI % 3) 1;
add(new HashMap<String, Object>(){{
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DAY_OF_MONTH, finalI);
put("userid", simulateID.toString() );
put("date", cal.getTime());
}});
}
}};
Map<String, ArrayList<Object>> map = list
.stream()
.collect(
Collectors.toMap(
e -> (String) e.get("userid"),
e -> new ArrayList<Object>(){{ add(e.get("date")); }},
(v1, v2) -> {
v1.addAll(v2);
return v1;
}
)
);
System.out.println(map);
}
}
But before using something like that maybe is better take a look in this article to see if it fit to your needs https://arnaudroger.github.io/blog/2017/06/13/jdbc-template-one-to-many.html
CodePudding user response:
Plain Java
public static <T> Map<String, List<T>> convert(List<Map<String, T>> items) {
Map<String, List<T>> map = new HashMap<>();
for (Map<String, T> item : items)
for (Map.Entry<String, T> entry : item.entrySet())
map.computeIfAbsent(entry.getKey(), key -> new ArrayList<>()).add(entry.getValue());
return map;
}
Stream
public static <T> Map<String, List<T>> convert(List<Map<String, T>> items) {
return items.stream()
.flatMap(item -> item.entrySet().stream())
.collect(Collectors.groupingBy(Map.Entry::getKey,
Collectors.mapping(Map.Entry::getValue,
Collectors.toList())));
}