Как получить многоуровневый агрегированный результат из карты, используя поток Java8 и groupBy? - PullRequest
0 голосов
/ 31 мая 2018

Я хочу получить агрегированный вывод из моей карты, используя функции группировки потоков.в основном я хочу многоуровневую групповую передачу с использованием потока.У меня есть карта с некоторыми данными, и я хочу, чтобы в качестве выходных данных была карта с агрегированными данными.

В целом в ней есть cityArea с различными областями PinP внутри.У каждого areaPin есть два раздела: 1 и 2. Я хочу суммировать соответствующий счетчик по разделам и хочу, чтобы данные агрегации на cityId.Пожалуйста, обратитесь ниже классов.Таким образом, у меня есть агрегированная информация по cityId + areaPin, и я хочу получить из нее агрегированную информацию по cityId.

CityArea:

public class CityArea {
String cityId;
String areaPin;
public String getCityId() {
    return cityId;
}
public void setCityId(String cityId) {
    this.cityId = cityId;
}
public String getAreaPin() {
    return areaPin;
}
public void setAreaPin(String areaPin) {
    this.areaPin = areaPin;
}
public CityArea(String cityId, String areaPin) {
    super();
    this.cityId = cityId;
    this.areaPin = areaPin;
}
public CityArea() {
    super();
}

}

ResourceCount:

public class ResourceCount {

Integer streetLightCount;
Integer waterTankCount;
public Integer getStreetLightCount() {
    return streetLightCount;
}
public void setStreetLightCount(Integer streetLightCount) {
    this.streetLightCount = streetLightCount;
}
public Integer getWaterTankCount() {
    return waterTankCount;
}
public void setWaterTankCount(Integer waterTankCount) {
    this.waterTankCount = waterTankCount;
}
public ResourceCount(Integer streetLightCount, Integer waterTankCount) {
    super();
    this.streetLightCount = streetLightCount;
    this.waterTankCount = waterTankCount;
}
public ResourceCount() {
    super();
}

}

Пример кода:

Map<CityArea, Map<Integer,ResourceCount>> map = new HashMap<>();

    CityArea ca1= new CityArea("cityId1", "1");
    CityArea ca2= new CityArea("cityId1", "2");

    CityArea ca3= new CityArea("cityId2", "1");
    CityArea ca4= new CityArea("cityId2", "2");

    ResourceCount resourceCount1 = new ResourceCount(10, 10);
    ResourceCount resourceCount2 = new ResourceCount(10, 10);

    Map<Integer,ResourceCount> resourceMap1 = new HashMap<>();
    resourceMap1.put(1, resourceCount1);
    resourceMap1.put(2, resourceCount2);

    map.put(ca1, resourceMap1);
    map.put(ca2, resourceMap1);

    Map<Integer,ResourceCount> resourceMap2 = new HashMap<>();
    resourceMap2.put(1, resourceCount1);
    resourceMap2.put(2, resourceCount2);

    map.put(ca3, resourceMap2);
    map.put(ca4, resourceMap2);

Ввод:

  {
  CityArea [cityId=cityId2, areaPin=2]=
  {1=ResourceCount [streetLightCount=10, waterTankCount=10],
   2=ResourceCount [streetLightCount=20, waterTankCount=20]},


 CityArea [cityId=cityId1, areaPin=2]=
 {1=ResourceCount [streetLightCount=10, waterTankCount=10],
  2=ResourceCount [streetLightCount=20, waterTankCount=20]}, 

 CityArea [cityId=cityId1, areaPin=1]=
 {1=ResourceCount [streetLightCount=10, waterTankCount=10],
 2=ResourceCount [streetLightCount=20, waterTankCount=20]},

 CityArea [cityId=cityId2, areaPin=1]=
 {1=ResourceCount [streetLightCount=10, waterTankCount=10],
 2=ResourceCount [streetLightCount=20, waterTankCount=20]}

 }

Ожидаемая карта вывода:

Map<String, Map<Integer, ResourceCount>>

cityId1 = {1=ResourceCount [streetLightCount=20, waterTankCount=20],
            2=ResourceCount [streetLightCount=40, waterTankCount=40]},

cityId2 = {1=ResourceCount [streetLightCount=20, waterTankCount=20],
            2=ResourceCount [streetLightCount=40, waterTankCount=40]}

Ответы [ 2 ]

0 голосов
/ 31 мая 2018

Попробуйте,

final Map<String, Map<Integer, ResourceCount>> destMap = map.entrySet().stream().collect(
        Collectors.toMap(entry -> entry.getKey().getCityId(), Map.Entry::getValue, (resMap1, resMap2) -> {
            return Stream.of(resMap1, resMap2).flatMap(m -> m.entrySet().stream())
                    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue,
                            (rc1, rc2) -> new ResourceCount(
                                    rc1.getStreetLightCount() + rc2.getStreetLightCount(),
                                    rc1.getWaterTankCount() + rc2.getWaterTankCount())));
        }));
0 голосов
/ 31 мая 2018

Сначала определите непосредственный класс для хранения ваших данных:

public class CityResource {
   String cityId;
   Integer areaPin;
   ResourceCount resource;
   // Constructor, getter, setter
}

Затем объедините ваши данные:

Map<CityArea, Map<Integer, ResourceCount>> input = ...;

Map<String, Map<Integer, ResourceCount>> output = 
input.entrySet().stream()
     .flatMap(e -> e.getValue().entrySet().stream().map(r -> new CityResource(e.getKey(), r.getKey(), r.getValue())))
     .collect(groupingBy(CityResource::getCityId, 
                  groupingBy(CityResource::getAreaPin, reducing(new ResourceCount(), (r1, r2) -> new ResourceCount(r1.getStreetLightCount() + r2.getStreetLightCount(), r1.getWaterTankCount() + r2.getWaterTankCount())))));
...