DMcg
DMcg

Reputation: 129

Java Stream Grouping by List<Map<String, Object>> to Map<Integer, List<Integer>>

I have a

List<Map<String, Object>>

coming from a Spring NamedParameterJdbcTemplate queryForList call. The data return looks like this:

[{"id":5,"uid":6}, {"id":5,"uid":7}, {"id":6,"uid":8}, {"id":7,"uid":7}, {"id":8,"uid":7}, {"id":8,"uid":9}]

How can I rearrange the data in the following format?

{5:[6, 7], 6:[8], 7:[7], 8:[7, 9]}

Im looking to return a Map<Integer, List<Integer>>

Anyone have an idea how I can achieve this? Any help much appreciated??

Upvotes: 2

Views: 6116

Answers (3)

Eugene
Eugene

Reputation: 120858

This is a job for Collectors.groupingBy with a downstream collector like Collectors.mapping

 Map<Integer, List<Integer>> result = l.stream()
            .collect(Collectors.groupingBy(
                    m -> (Integer) (m.get("id")),
                    Collectors.mapping(m -> (Integer) m.get("uuid"), Collectors.toList())));

Or without streams at all:

list.forEach(x -> {
        Integer key = (Integer) x.get("id");
        Integer value = (Integer) x.get("uuid");
        result.computeIfAbsent(key, ignoreMe -> new ArrayList<>()).add(value);
    });

Upvotes: 7

Andy Turner
Andy Turner

Reputation: 140318

I am not a huge fan of the syntax of the streams API: I think it might be easier to do using a plain old loop (with a few other Java 8-isms):

Map<Integer, List<Integer>> result = new HashMap<>();
for (Map<String, Object> entry : list) {
  int id = (Integer) entry.get("id");
  int uid = (Integer) entry.get("uid");
  result.computeIfAbsent(id, k -> new ArrayList<>())
      .add(uid);
}

YMMV, of course; I just think this is more pleasant than all of the faffing around with collectors and downstream collectors, and the non-obvious error messages when you make type errors.

Upvotes: 0

ernest_k
ernest_k

Reputation: 45319

You can map keys and values to integers while using a grouping-by collector:

List<Map<String, Object>> maps = null;

Map<Integer, List<Integer>> result = maps.stream()
        .collect(Collectors.groupingBy(
                map -> ((Number) map.get("id")).intValue(),
                    Collectors.mapping(map -> ((Number) map.get("uid")).intValue(), 
                            Collectors.toList())));

Using ((Number) map.get("id")).intValue() just in case the value is a Long.

Upvotes: 3

Related Questions