Java GroupBy, кратный сумме

Я пытаюсь сделать group by как в mySQL, у меня есть несколько столбцов (свойств), и я должен сгруппировать по двум полям (socio и idSolicitudEgreso) и суммировать еще одно (montoPago). Я сделал:

Map<String, Map<String, Integer>> mymap = santa.stream()
        .collect(Collectors.groupingBy(Santander::getPanSocio,
                 Collectors.groupingBy(Santander::getPanIdsolicitudegreso,
                 Collectors.summingInt(Santander::getPanMontopago))));

mymap.forEach((key, value) -> System.out.println(key + ":" + value));

Мой объект класса:

public class Santander {

    private String panRutbeneficiario;
    private String panNombrebeneficiario;
    private String panEmailbeneficiario;
    private String panMetodopago;
    private String panCodigobancoabono;
    private String panTipocuentaabono;
    private String panNumcuentaabono;
    private String panFechapago;
    private String panCampobanco1;
    private String panCampobanco2;
    private int panMontopago;
    private String panTipocuentacargodet;
    private String panNumcuentacargodet;
    private String panCodigosucursal;
    private String panReferenciacliente;
    private String panRetencionfactura;
    private String panAbonovalesvistalinea;
    private String panCantidaddocumentos;
    private String panSocio;
    private String panIdsolicitudegreso;
}

Я получаю этот результат с этим кодом:

БАНКО ДЕЛЬ ЭСТАДО:{35113=3026882}

Как видите, я очень хорошо получаю группу (также socio, id и sum), но мне нужно получить все объекты или список объектов. Я просто получаю 3 из 20 полей. Какое изменение я должен внести в свой код потока Java, чтобы получить список объектов (сгруппированных)? Пожалуйста?

Спасибо

PS: результат, который я ожидаю:

{  panRutbeneficiario=146174558, panNombrebeneficiario=No Definido,
   panEmailbeneficiario=, panMetodopago=CAT_CSH_TRANSFER, panCodigobancoabono=12,
   panTipocuentaabono=Ahorro, panNumcuentaabono=8275301, panFechapago=2020-07-30,
   panCampobanco1=, panCampobanco2=, panMontopago=111960,
   panTipocuentacargodet=CAT_CSH_CCTE, panNumcuentacargodet=null,
   panCodigosucursal=, panReferenciacliente=, panRetencionfactura=,
   panAbonovalesvistalinea=null, panCantidaddocumentos=null, 
   panSocio=BANCO DEL ESTADO, panIdsolicitudegreso=35113
}

person Jhon Masco    schedule 24.09.2020    source источник
comment
Можете ли вы уточнить список объектов, которые вы ожидаете? Пожалуйста, попробуйте предоставить ожидаемый результат.   -  person Alex Rudenko    schedule 24.09.2020
comment
Не совсем понятно из но мне нужно получить весь объект или список объектов.. Если вы не выполняете summingInt, который уменьшает внутренние значения до Integer суммы одного поля, внутренние значения будут List<Santander>, если это то, чего вы ожидаете. Затем вы можете перебрать этот список и суммировать его panMontopago. например Map<String, Map<String, List<Santander>>> mymap = santa.stream().collect(Collectors.groupingBy(Santander::getPanSocio, Collectors.groupingBy(Santander::getPanIdsolicitudegreso)));, а затем выполните get на этом Map по желанию.   -  person Naman    schedule 24.09.2020
comment
{panRutbeneficiario=146174558, panNombrebeneficiario=No Definido, panEmailbeneficiario=, panMetodopago=CAT_CSH_TRANSFER, panCodigobancoabono=12, panTipocuentaabono=Ahorro, panNumcuentaabono=8275301, panFechapago=2020-07-30, panCampobanco1=, panCampobanco2=, panMontopago=111960, panTipocuentacargodet=CAT_CSH_CCTE , panNumcuentacargodet=null, panCodigosucursal=, panReferenciacliente=, panRetencionfactura=, panAbonovalesvistalinea=null, panCantidaddocumentos=null, panSocio=BANCO DEL ESTADO, panIdsolicitudegreso=35113} Этого я ожидаю, Whete panMontopago суммируется   -  person Jhon Masco    schedule 24.09.2020
comment
Наман, я понял твою идею, но я подумал, что можно сделать это в одном предложении. Во всяком случае я возьму вас идея на некоторое время. Спасибо   -  person Jhon Masco    schedule 24.09.2020
comment
Намман, я попробовал ваше решение, и я получил длинный список без группировки, потому что getPanMontopago (деньги) разные в каждой строке. Я хотел бы сгруппировать только одну строку, но для этого мне нужна сумма getPanMontopago. Я не буду делать сумму, повторяющую список, и создавать свою собственную строку, потому что я не могу предположить, что у меня всегда будет только один (равный) Socio или ID.   -  person Jhon Masco    schedule 24.09.2020
comment
@JhonMasco, зачем тебе List<Santander>? Какие значения должны быть предоставлены для полей, не входящих в группу?   -  person Alex Rudenko    schedule 24.09.2020


Ответы (1)


Вам может понадобиться подготовить объект для хранения результата группировки, например:

public class Summary {
    private final String panSocio;
    private final String panSolicitude;
    private final int total;

    public Summary(String socio, String solicitude, int total) {
        this.panSocio = socio;
        this.panSolicitude = solicitude;
        this.total = total;
    }

    public String getPanSocio() { return this.panSocio; }
    public String getPanSolicitude() { return this.panSolicitude; }
    public int getTotal() { return this.total; }

    public String toString() {
        return String.format("{ socio=\"%s\", solicitude=\"%s\", total=%d}%n",
                panSocio, panSolicitude, total);
    }
}

Затем можно перебрать записи mymap, использовать flatMap для преобразования записей внутренней карты в Stream<Summary>, таким образом собирая в список Summary объектов (при необходимости отсортированных):

List<Summary> remap = mymap.entrySet()
        .stream()
        .flatMap(e -> e.getValue().entrySet()  // e.getKey() -> panSocio
                       .stream()               // ee.getKey() -> solicitude, ee.getValue() -> total
                       .map(ee -> new Summary(e.getKey(), ee.getKey(), ee.getValue()))
        )
        .sorted(Comparator.comparing(Summary::getPanSocio)
                          .thenComparing(Summary::getPanSolicitude))
        .collect(Collectors.toList());

Обновить

Конечно, можно повторно использовать существующий класс Santander для сбора результатов при условии, что Santander имеет конструктор или построитель, позволяющий заполнить как минимум три соответствующих поля panSocio, panSolicitude, panMontopago:

List<Santander> grouped = mymap.entrySet()
        .stream()
        .flatMap(e -> e.getValue().entrySet()  // e.getKey() -> panSocio
                       .stream()               // ee.getKey() -> solicitude, ee.getValue() -> total
                       .map(ee -> new Santander(e.getKey(), ee.getKey(), ee.getValue())) // the rest of the fields set to some default values
        )
        .collect(Collectors.toList());

Однако остальные поля Santander будут неопределенными/по умолчанию после применения коллектора summarizingInt пользователем Santander::getMontopago.

person Alex Rudenko    schedule 24.09.2020
comment
откуда sorted появляется на картинке? - person Naman; 24.09.2020
comment
@Naman, сортировка не является обязательной, как я уже упоминал в ответе. Я сделал список результатов отсортированным а) например, б) как незначительное улучшение, потому что в тестовом выводе (здесь не приводится) порядок списка был случайным. - person Alex Rudenko; 24.09.2020
comment
Спасибо Алекс за ответ. - person Jhon Masco; 25.09.2020