Группировка класса с использованием потока Java 8 или SQL, в зависимости от того, что лучше - PullRequest
0 голосов
/ 02 ноября 2019

Данные выглядят примерно так

    head child assigned total
[   Mas   Mas1     2    5
,   Mas   Mas2     0    5
,   Usr   usr1     4    4
,   Usr   usr2     1    3
,   Inv   Inv1     3    5
,   Inv   Inv2     2    3
,   Inv   Inv3     2    3
,   Inv   Inv4     1    3
]

Я хочу получить сумму их дочернего элемента для определенного заголовка.

Я использую раздел в sql

select head,
SUM(childAssigned) over (partition by am.acl_group) as assignedHead,
sum(childTotal) over (partition by am.acl_group) as totalHead,
child,
childAssigned,
childTotal

Поскольку "разбиение по" не поддерживается HQL astquerytranslatorfactory, я использую его как собственный запрос

У меня есть класс, который содержит ответ SQL

class AclList{
    String head;
    Integer assignedHead;
    Integer totalHead;
    String child;
    Integer assignedChild;
    Integer totalChild;
}

Данные выглядят примерно такthis

[   Mas 2   10  Mas1    2   5
,   Mas 2   10  Mas2    0   5
,   Usr 5   7   usr1    4   4
,   Usr 5   7   usr2    1   3
,   Inv 8   14  Inv1    3   5
,   Inv 8   14  Inv2    2   3
,   Inv 8   14  Inv3    2   3
,   Inv 8   14  Inv4    1   3
]

Мне нужен ответ, который будет группировать дочерний элемент того же заголовка.

Ответ должен быть похож на ResponseClass (тип, назначенный, всего, список)

[ 
  { 
    "type":"MAS",
    "assigned":"2",
    "total":"10",
    "subType":[ 
      { 
        "type":"MAS1",
        "assigned":"2",
        "total":"5"
      },
      { 
        "type":"MAS2",
        "assigned":"0",
        "total":"5"
      }
    ]
  },
  { 
    "type":"USR",
    "assigned":"5",
    "total":"7",
    "subType":[ 
      { 
        "type":"USR1",
        "assigned":"4",
        "total":"4"
      },
      { 
        "type":"USR2",
        "assigned":"1",
        "total":"3"
      }
    ]
  }
]

Сведения о классе (тип, назначено, всего) Мой подход заключается в том, чтобы сохранить заголовок в ключе hashmap, потомок в значении hashmap Так как все 3 столбца заголовка одинаковы, поэтому, равняется, заботится о hashcode.

class ChildDetails (List) HashMap

Iterate sql response
if hashmap.contains(head) //exist
    fetch value, add new one in list
    hashmap.put(head, updated)
else
    create header,
    create child, add it to a blank list
    hashmap.put(head, new list)

Снова итерируйте hashmap, разместите его в новом ответе json

Но это громоздкий и неэффективный процесс.

Есть ли он в любом случае? сделано с потоком JAVA ()?

Ответы [ 2 ]

1 голос
/ 02 ноября 2019

Да, это можно сделать с помощью потока JAVA ()

package com.bbc.enums;

import lombok.*;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.*;
import java.util.stream.Collectors;


public class StackOverFlow {
    public static void main(String[] args) {
        List<AclList> aclLists = Arrays.asList(
                new AclList("Mas", 2, 10, "Mas1", 2, 5),
                new AclList("Mas", 2, 10, "Mas2", 0, 5),
                new AclList("USR", 5, 7, "USR1", 4, 4),
                new AclList("USR", 5, 7, "USR2", 1, 3),
                new AclList("Inv", 8, 14, "Inv1", 3, 5),
                new AclList("Inv", 8, 14, "Inv2", 2, 3),
                new AclList("Inv", 8, 14, "Inv3", 2, 3),
                new AclList("Inv", 8, 14, "Inv4", 1, 3)

        );

        Map<String, Map<Integer, Map<Integer, List<AclList>>>> collect = aclLists.stream()
                .collect(Collectors.groupingBy(AclList::getHead, Collectors.groupingBy(AclList::getAssignedHead,
                        Collectors.groupingBy(AclList::getTotalHead))));

        List<HashMap<String, Object>> resList = new ArrayList<>();
        collect.forEach((k1, v1) -> {
            HashMap<String, Object> res = new HashMap<>();
            res.put("type", k1);
            v1.forEach((k2, v2) -> {
                res.put("assigned", k2);
                v2.forEach((k3, v3) -> {
                    res.put("total", k3);
                    List<HashMap<String, Object>> list = new ArrayList<>();
                    v3.forEach(aclList -> {
                        HashMap<String, Object> map1 = new HashMap<>();
                        map1.put("type", aclList.getChild());
                        map1.put("assigned", aclList.getAssignedChild());
                        map1.put("total", aclList.getTotalChild());
                        list.add(map1);
                    });
                    res.put("subType", list);
                });
            });
            resList.add(res);
        });
        System.out.println(resList);
        // if you want json response then
        System.out.println(listmap_to_json_string(resList));
    }


    public static String listmap_to_json_string(List<HashMap<String, Object>> list) {
        JSONArray json_arr = new JSONArray();
        for (Map<String, Object> map : list) {
            JSONObject json_obj = new JSONObject();
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                String key = entry.getKey();
                Object value = entry.getValue();
                try {
                    json_obj.put(key, value);
                } catch (JSONException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            json_arr.put(json_obj);
        }
        return json_arr.toString();
    }
}


@AllArgsConstructor
@Getter
@Setter
@ToString
@NoArgsConstructor
class AclList {
    String head;
    Integer assignedHead;
    Integer totalHead;
    String child;
    Integer assignedChild;
    Integer totalChild;
}
1 голос
/ 02 ноября 2019

Здесь может помочь Collectors.groupingBy stream Collector.

Настройка:

// original data AclList
class AclList {

  String head;
  Integer assignedHead;
  Integer totalHead;
  String child;
  Integer assignedChild;
  Integer totalChild;
}

// Subtype in the response object based on Json
class SubType {

  String type;
  Integer assigned;
  Integer total;

  public SubType(String type, Integer assigned, Integer total) {
    this.type = type;
    this.assigned = assigned;
    this.total = total;
  }
}

// Response object based on Json
class Response {

  String type;
  Integer assigned;
  Integer total;
  List<SubType> subType;

  public Response(String type, Integer assigned, Integer total, List<SubType> subType) {
    this.type = type;
    this.assigned = assigned;
    this.total = total;
    this.subType = subType;
  }
}

Шаг 1: Сгруппировать данные по полю head в классе AclList. Этот шаг возвращает Map различных head значений в качестве ключа и список AclList объектов в качестве значения, сгруппированных по ключу.

Map<String, List<AclList>> groupedByHead = data
    .stream()
    .collect(Collectors.groupingBy(acl -> acl.head));

Шаг 2: Просто манипулируйте Map, чтобы создать требуемую структуру ответа.

List<Response> response = groupedByHead.entrySet()
    .stream()
    .filter(e -> e.getValue().size() > 0)
    .map(e -> {
          List<AclList> acls = e.getValue();
          AclList first = acls.get(0);
          List<SubType> children = acls
              .stream()
              .map(acl -> new SubType(acl.child, acl.assignedChild, acl.totalChild))
              .collect(Collectors.toList());

          return new Response(first.head, first.assignedHead, first.totalHead, children);
    })
    .collect(Collectors.toList());

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

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