Сгруппируйте список объектов для создания расширенного списка объектов - PullRequest
4 голосов
/ 20 июня 2019

У меня есть эти примеры записей из базы данных, которая является результатом группировки по запросу:

[
 {
   "name": "Troy",
   "acct": 1123,
   "type": " Savings",
   "total": 50
 },
 {
   "name": "Larry",
   "acct": 4233,
   "type": " Savings",
   "total": 200
 },
 {
   "name": "Troy",
   "acct": 1123,
   "type": " Current",
   "total": 120
 },
 {
   "name": "Larry",
   "acct": 4233,
   "type": " Current",
   "total": 220
 }
]

Теперь мне нужно создать отчет, который выглядит так:

[
 {
   "name": "Troy",
   "acct": 1123,
   "totalSavings": 50,
   "totalCurrent": 120
 },
 {
   "name": "Larry",
   "acct": 4233,
   "totalSavings": 200,
   "totalCurrent": 220
 }
]

.

public class DbTrans {
    private String name;
    private String acct;
    private String type;
    private double total;

// getters and setters
...
}

Я пытался использовать некоторые лямбда-техники, подобные приведенным ниже, но я все еще не могу приблизиться к желаемому решению.

 Map<String, List<DbTrans>> collect = transList.stream().collect(
          Collectors.groupingBy(f -> f.getType()));

Ответы [ 2 ]

5 голосов
/ 20 июня 2019

Прежде всего, ответ Dto не совпадает с запросом Dto, я предлагаю создать новый класс Response, чтобы он не вызывался:

public class DbTransResponse {
    private String name;
    private String acct;
    private double totalSavings;
    private double totalCurrent;
    // getters and setters
}

тогда результат может быть таким:

List<DbTransResponse> result = transList.stream()
        .collect(Collectors.groupingBy(DbTrans::getAcct))
        .values().stream()
        .map(trans -> new DbTransResponse(
                trans.get(0).getName(),
                trans.get(0).getAcct(),
                trans.get(0).getTotal(),
                trans.get(1).getTotal()
        )).collect(Collectors.toList());

Я считаю, что список должен содержать две записи каждого имени, чтобы вы могли получить totalSavings из первой записи trans.get(0).getTotal() и totalCurrent из второй trans.get(1).getTotal().

Если вы не уверены, что можете использовать условия для заполнения вашего объекта, например, вы можете проверить, есть ли два элемента, если не установить значение по умолчанию.


Демо Ideone

Результаты

DbTransResponse{name='Larry', acct='4233', totalSavings=200.0, totalCurrent=220.0}
DbTransResponse{name='Troy', acct='1123', totalSavings=50.0, totalCurrent=120.0}
2 голосов
/ 21 июня 2019

Вы можете использовать Collectors::toMap для этой цели (с одной collect операцией)

 Map<Integer, DbTransResponse> collect = transList.stream()
            .collect(Collectors.toMap(DbTrans::getAcct, 
                                      DbTransResponse::new, 
                                      DbTransResponse::merge));

 Collection<DbTransResponse> result = collect.values();

вот метод слияния в DbTransResponse классе

static DbTransResponse merge(DbTransResponse r1, DbTransResponse r2) {
        return new DbTransResponse(
                r1.name, r1.acct,
                r1.totalSavings + r2.totalSavings,
                r1.totalCurrent + r2.totalCurrent
        );
    }

и дополнительный конструктор для DbTransResponse класса, хотя вы можете переместить эту логику в метод

DbTransResponse(DbTrans dbTrans) {
   this.name = dbTrans.getName();
   this.acct = dbTrans.getAcct();
   this.totalSavings = "Savings".equals(dbTrans.getType()) ? dbTrans.getTotal() : 0;
   this.totalCurrent = "Current".equals(dbTrans.getType()) ? dbTrans.getTotal() : 0;

}

демо

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...