简体   繁体   中英

Using java 8 streams to build a map of map from another map of map

I have a Map collection in java

Map<AreaDate, Map<AreaCategory, List<Location>> dateWiseAreas

using java 8 I want to build a map of

 Map<Area, Map<AreaCategory, List<Location>> areas

I used the below logic and I get a duplicate key error saying Area key is duplicate

Map<Area, Map<AreaCategory, List<Location>> areas =  dateWiseAreas.entrySet().stream()
.collect(toMap(k -> k.getKey().area(),
               v -> v.getValue()
                     .entrySet()
                     .stream()
                     .collect(Collectors.toMap(Map.Entry::getKey(), Map::Entry::getValue,
                             (oldValue,newValue) -> oldValue, LinkedHashMap::new))));

Java classes

Area {
   EUROPE,
   AUSTRALIA,
   ASIA;   
}


AreaDate {
 Area area;
 LocalDate date;
 int priority;
}

AreaCategory {
  NORTH,
  SOUTH,
  WEST,
  EAST;
}

Location {
 int xaxis;
 int yaxis;
}

You need to use the 3 argument version of toMap in the outer collect to avoid conflict on keys where the same area is found multiple times with different dates.

Something like (untested)

Map<Area, Map<AreaCategory, List<Location>> areas =  dateWiseAreas.entrySet().stream()
.collect(toMap(k -> k.getKey().area(),
               v -> v.getValue()
                     .entrySet()
                     .stream()
                     .collect(Collectors.toMap(Map.Entry::getKey(), Map::Entry::getValue,
                             (oldValue,newValue) -> oldValue, LinkedHashMap::new)),
              (oldValue, newvalue) -> oldValue
));

You can use the overload of toMap() which allows you to pass a BinaryOperator<V> where V in your case is Map<AreaCategory, List<Location>>

Map<Area, Map<AreaCategory, List<Location>> areas = dateWiseAreas.entrySet().stream()
    .collect(Collectors.toMap(
        e -> e.getKey().area(),
        Map.Entry::getValue, // there seems to be no need to copy the whole thing again
        (a, b) -> {
            // merging Map b into Map a
            b.forEach((key, values) -> a.merge(key, values, (c, d) -> {
                // adding all locations from d to a
                c.addAll(d);
                return c;
            });
            return b;
        })
    );

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM