如何重构非标准结构的树形结构数据
大家好!不知你在java编程过程中,是否遇到过非标准数据结构的数据对象,需要进行数据重组成java中的树形对象,再返给前端?
昨日
为了尽快让前端拿到测试数据,应付着先写了个性能很差劲的,调用了大量的mybatis查询,导致性能很慢:
1.先说数据结构:
工厂-车间-线体
工厂具有工厂名称,代码,车间集合三个属性;
车间具有车间名称,代码,线体集合三个属性;
2. 然而数据库中往往只能查询到,工厂名称、工厂代码、车间名称、车间代码、线体名称、线体代码这类似的平铺数据集合。
3. 如何将数据组装好返回给前端展示呢?
4. 简单粗暴的就是遍历,先查返回的工厂,然后再把工厂带进查询车间的查询条件中,再把工厂和车间带到查询线体的条件中。
5. 比如这样??
List<AppSaleReqConditionDto> queryFactoryInfo(@Param("scheduleNo") String scheduleNo, @Param("symbol") String symbol,@Param("scheduleDate") String scheduleDate);
List<AppSaleReqConditionDto.AppTreeWorkshop> queryWorkShopInfo(@Param("factoryCode") String factoryCode,@Param("scheduleNo") String scheduleNo, @Param("symbol") String symbol,@Param("scheduleDate") String scheduleDate);
List<AppSaleReqConditionDto.AppTreeLines> queryLineInfo(@Param("factoryCode") String factoryCode,@Param("workshopCode") String workshopCode,@Param("scheduleNo") String scheduleNo, @Param("symbol") String symbol,@Param("scheduleDate") String scheduleDate);
- 然而这样会再次通过数据库查询多次数据库,性能影响太大。
代码优化
1.今天,抽出空余时间,想对这个问题进行优化一下。如何优化?查询平铺数据后,用程序组装数据结构,但是数据结构不是简单的父子节点,相同的数据结构。
2.那就不用递归,直接遍历。
3.核心代码:
/**
* 重构平铺数据为树形结构
*
* @param list
* @param result
* @return
*/
public List<AppSaleReqConditionDto> refactorData(List<AppFactoryWorkShopLineDto> list, List<AppSaleReqConditionDto> result) {
for (int i = 0; i < list.size(); i++) {
AppFactoryWorkShopLineDto item = list.get(i);
boolean containsFactory = AppSaleReqConditionDto.isContainsFactory(result, item);
if (!containsFactory) {
result.add(new AppSaleReqConditionDto(item.getFactoryName(), item.getFactoryCode()));
}
boolean containsWorkShop = AppSaleReqConditionDto.isContainsWorkShop(result, item);
if (!containsWorkShop) {
for (int j = 0; j < result.size(); j++) {
AppSaleReqConditionDto itemFactory = result.get(j);
if (itemFactory.getFactoryCode().equals(item.getFactoryCode()) && itemFactory.getFactoryName().equals(item.getFactoryName())) {
itemFactory.getWorkshops().add(new AppSaleReqConditionDto.AppTreeWorkshop(item.getWorkshopName(), item.getWorkshopCode()));
}
}
}
boolean containsLine = AppSaleReqConditionDto.isContainsLine(result, item);
if (!containsLine) {
for (int j = 0; j < result.size(); j++) {
AppSaleReqConditionDto itemFactory = result.get(j);
for (int k = 0; k < itemFactory.getWorkshops().size(); k++) {
AppSaleReqConditionDto.AppTreeWorkshop itemWorkShop = itemFactory.getWorkshops().get(k);
if (itemFactory.getFactoryCode().equals(item.getFactoryCode()) && itemFactory.getFactoryName().equals(item.getFactoryName()) &&
itemWorkShop.getWorkshopCode().equals(item.getWorkshopCode()) && itemWorkShop.getWorkshopName().equals(item.getWorkshopName())) {
itemWorkShop.getLines().add(new AppSaleReqConditionDto.AppTreeLines(item.getLineName(), item.getLineCode()));
}
}
}
}
}
return result;
}
public static boolean isContainsFactory(List<AppSaleReqConditionDto> list, AppFactoryWorkShopLineDto strDto) {
boolean flag = false;
if (CollectionUtils.isNotEmpty(list)) {
for (int i = 0; i < list.size(); i++) {
AppSaleReqConditionDto item = list.get(i);
if (item.getFactoryCode().equals(strDto.getFactoryCode()) && item.getFactoryName().equals(strDto.getFactoryName())) {
flag = true;
break;
}
}
}
return flag;
}
public static boolean isContainsWorkShop(List<AppSaleReqConditionDto> list, AppFactoryWorkShopLineDto strDto) {
boolean flag = false;
if (CollectionUtils.isNotEmpty(list)) {
for (int i = 0; i < list.size(); i++) {
AppSaleReqConditionDto item = list.get(i);
List<AppTreeWorkshop> workshops = item.getWorkshops();
if (CollectionUtils.isNotEmpty(workshops)) {
for (int j = 0; j < workshops.size(); j++) {
AppTreeWorkshop itemWorkshop = workshops.get(j);
List<AppTreeLines> lines = itemWorkshop.getLines();
if (itemWorkshop.getWorkshopCode().equals(strDto.getWorkshopCode()) && itemWorkshop.getWorkshopName().equals(strDto.getWorkshopName())) {
flag = true;
break;
}
}
}
}
}
return flag;
}
public static boolean isContainsLine(List<AppSaleReqConditionDto> list, AppFactoryWorkShopLineDto strDto) {
boolean flag = false;
if (CollectionUtils.isNotEmpty(list)) {
for (int i = 0; i < list.size(); i++) {
AppSaleReqConditionDto item = list.get(i);
List<AppTreeWorkshop> workshops = item.getWorkshops();
if (CollectionUtils.isNotEmpty(workshops)) {
for (int j = 0; j < workshops.size(); j++) {
AppTreeWorkshop itemWorkshop = workshops.get(j);
List<AppTreeLines> lines = itemWorkshop.getLines();
if (CollectionUtils.isNotEmpty(lines)) {
for (int k = 0; k < lines.size(); k++) {
AppTreeLines line = lines.get(k);
if (line.getLineCode().equals(strDto.getLineCode()) && line.getLineName().equals(strDto.getLineName())) {
flag = true;
}
}
}
}
}
}
}
return flag;
}
4.平铺数据结构:
@Data
@NoArgsConstructor
@ApiModel(value = "工厂-车间-线体 平铺数据")
public class AppFactoryWorkShopLineDto {
@ApiModelProperty(value = "工厂名字")
private String factoryName;
@ApiModelProperty(value = "工厂代码")
private String factoryCode;
@ApiModelProperty(value = "工厂-车间名字")
private String workshopName;
@ApiModelProperty(value = "工厂-车间代码")
private String workshopCode;
@ApiModelProperty(value = "线体代码")
private String lineCode;
@ApiModelProperty(value = "线体名称")
private String lineName;
}
5.想要得到的数据结构:
public class AppSaleReqConditionDto {
@ApiModelProperty(value = "工厂名字")
private String factoryName;
@ApiModelProperty(value = "工厂-车间数组")
private List<AppTreeWorkshop> workshops;
@ApiModelProperty(value = "工厂代码")
private String factoryCode;
public AppSaleReqConditionDto(String factoryName, String factoryCode) {
this.factoryName = factoryName;
this.factoryCode = factoryCode;
this.workshops = new ArrayList<>();
}
@Data
@NoArgsConstructor
public static class AppTreeWorkshop {
@ApiModelProperty(value = "工厂-车间名字")
private String workshopName;
@ApiModelProperty(value = "工厂-车间代码")
private String workshopCode;
@ApiModelProperty(value = "工厂-车间-线体数组")
private List<AppTreeLines> lines;
public AppTreeWorkshop(String workshopName, String workshopCode) {
this.workshopName = workshopName;
this.workshopCode = workshopCode;
this.lines = new ArrayList<>();
}
}
@Data
@NoArgsConstructor
public static class AppTreeLines {
@ApiModelProperty(value = "线体代码")
private String lineCode;
@ApiModelProperty(value = "线体名称")
private String lineName;
public AppTreeLines(String lineCode, String lineName) {
this.lineCode = lineCode;
this.lineName = lineName;
}
}
}
分析总结
树形结构处理,很自然的想到递归函数来处理,得到树形结构数据。然而非正常的上下级父子关系,递归函数显得有点苍白乏力。
单靠数据库查询条件重复带入也是可以获取到一样的数据结构,但是性能上不在一个等级。能够使用内存处理数据,不建议重复调用数据库查询。