mirror of https://github.com/alibaba/easyexcel
2 changed files with 223 additions and 0 deletions
@ -0,0 +1,132 @@
|
||||
package com.alibaba.excel.util; |
||||
import org.apache.commons.compress.utils.Lists; |
||||
import org.apache.commons.math3.util.Pair; |
||||
|
||||
import java.util.*; |
||||
import java.util.stream.Collectors; |
||||
|
||||
/** |
||||
* @author phaeris |
||||
* @since 2023/12/15 |
||||
*/ |
||||
public class PivotUtils { |
||||
|
||||
private PivotUtils() {} |
||||
|
||||
/** |
||||
* get pivot table head and data |
||||
* |
||||
* @param rowFields pivot row fields |
||||
* @param columnFields pivot column fields |
||||
* @param aggFields aggregator fields |
||||
* @param data original data |
||||
* @return head & data |
||||
*/ |
||||
public static Pair<List<List<String>>, List<List<Object>>> getHeadAndData(List<String> rowFields, List<String> columnFields, List<String> aggFields, |
||||
List<Map<String, Object>> data) { |
||||
return getHeadAndData(rowFields, columnFields, aggFields, null, data); |
||||
} |
||||
|
||||
/** |
||||
* get pivot table head and data |
||||
* |
||||
* @param rowFields pivot row fields |
||||
* @param columnFields pivot column fields |
||||
* @param aggFields aggregator fields |
||||
* @param alias alias mapping |
||||
* @param data original data |
||||
* @return head & data |
||||
*/ |
||||
public static Pair<List<List<String>>, List<List<Object>>> getHeadAndData(List<String> rowFields, List<String> columnFields, List<String> aggFields, |
||||
Map<String, String> alias, List<Map<String, Object>> data) { |
||||
//current row size empty data
|
||||
final List<Object> emptyRowData = rowFields.stream().map(x -> null).collect(Collectors.toList()); |
||||
//current column size empty data
|
||||
final List<Object> emptyColData = columnFields.stream().map(x -> null).collect(Collectors.toList()); |
||||
|
||||
//left top head
|
||||
List<List<String>> centerHeadPart = rowFields.stream().map(col -> { |
||||
List<String> centerHead = new ArrayList<>(columnFields); |
||||
centerHead.add(col); |
||||
return centerHead; |
||||
}).collect(Collectors.toList()); |
||||
//aggregator head
|
||||
List<List<String>> aggHeadPart = Lists.newArrayList(); |
||||
|
||||
//data init, fill row data
|
||||
Map<List<Object>, List<Object>> dataList = data.stream() |
||||
.map(row -> getGroup(row, rowFields, emptyRowData)) |
||||
.distinct() |
||||
.collect(Collectors.toMap(x -> x, ArrayList::new, (o, n) -> n, LinkedHashMap::new)); |
||||
//original data group by columns
|
||||
Map<List<Object>, List<Map<String, Object>>> groupByCols = data.stream() |
||||
.collect(Collectors.groupingBy(row -> getGroup(row, columnFields, emptyColData), LinkedHashMap::new, Collectors.toList())); |
||||
|
||||
//fill aggregator head and data
|
||||
for (Map.Entry<List<Object>, List<Map<String, Object>>> eachColData : groupByCols.entrySet()) { |
||||
//each column head
|
||||
List<String> colHead = eachColData.getKey().stream() |
||||
.map(x -> Objects.isNull(x) ? StringUtils.EMPTY : String.valueOf(x)) |
||||
.collect(Collectors.toList()); |
||||
//each col data group by row
|
||||
Map<List<Object>, List<Map<String, Object>>> groupByRows = eachColData.getValue() |
||||
.stream() |
||||
.collect(Collectors.groupingBy(x -> getGroup(x, rowFields, emptyRowData))); |
||||
//aggregator head nums: column data size * aggregator nums
|
||||
for (String aggField : aggFields) { |
||||
//col head
|
||||
List<String> copyColHead = new ArrayList<>(colHead); |
||||
copyColHead.add(aggField); |
||||
aggHeadPart.add(copyColHead); |
||||
//this col all data for each row
|
||||
dataList.forEach((originalRowData, finalRowData) -> { |
||||
List<Map<String, Object>> curRowData = groupByRows.get(originalRowData); |
||||
if (curRowData != null && !curRowData.isEmpty()) { |
||||
//group by column and row, get first
|
||||
finalRowData.add(curRowData.get(0).get(aggField)); |
||||
} else { |
||||
//no match, fill empty
|
||||
finalRowData.add(null); |
||||
} |
||||
}); |
||||
} |
||||
} |
||||
|
||||
//merge and replace alias head
|
||||
centerHeadPart.addAll(aggHeadPart); |
||||
List<List<String>> head = centerHeadPart.stream() |
||||
.map(x -> x.stream().map(c -> getAlias(alias, c)).collect(Collectors.toList())) |
||||
.collect(Collectors.toList()); |
||||
|
||||
return Pair.create(head, new ArrayList<>(dataList.values())); |
||||
} |
||||
|
||||
/** |
||||
* get group |
||||
* |
||||
* @param row row data |
||||
* @param fields fields |
||||
* @param emptyData or else empty data object |
||||
* @return group |
||||
*/ |
||||
private static List<Object> getGroup(Map<String, Object> row, List<String> fields, List<Object> emptyData) { |
||||
List<Object> dataList = fields.stream() |
||||
.map(row::get) |
||||
.collect(Collectors.toList()); |
||||
List<Object> nonNull = dataList.stream().filter(Objects::nonNull).collect(Collectors.toList()); |
||||
return nonNull.isEmpty() ? emptyData : dataList; |
||||
} |
||||
|
||||
/** |
||||
* get head alias |
||||
* |
||||
* @param alias alias mapping |
||||
* @param field field |
||||
* @return alias of field |
||||
*/ |
||||
private static String getAlias(Map<String, String> alias, String field) { |
||||
return alias != null && !alias.isEmpty() && StringUtils.isNotBlank(alias.get(field)) |
||||
? alias.get(field) |
||||
: field; |
||||
} |
||||
} |
@ -0,0 +1,91 @@
|
||||
package com.alibaba.easyexcel.test.core.pivot; |
||||
|
||||
import com.alibaba.excel.EasyExcelFactory; |
||||
import com.alibaba.excel.ExcelWriter; |
||||
import com.alibaba.excel.util.ListUtils; |
||||
import com.alibaba.excel.util.PivotUtils; |
||||
import com.alibaba.excel.write.metadata.WriteSheet; |
||||
import org.apache.commons.math3.util.Pair; |
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* @author phaeris |
||||
* @since 2023/12/15 |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
public class PivotTest { |
||||
|
||||
private static final String EXPORT_FILE_PATH = "C:\\Users\\A11-9\\Desktop\\excel\\pivot.xlsx"; |
||||
|
||||
private static final String SHEET_NAME = "pivot"; |
||||
|
||||
public static final List<String> ROW_FIELDS = ListUtils.newArrayList("address"); |
||||
|
||||
public static final List<String> COLUMN_FIELDS = ListUtils.newArrayList("name", "phone"); |
||||
|
||||
public static final List<String> AGG_FIELDS = ListUtils.newArrayList("age", "height"); |
||||
|
||||
private static final Map<String, String> ALIAS; |
||||
|
||||
private static final List<Map<String, Object>> DATA; |
||||
|
||||
static { |
||||
Map<String, Object> row1 = new HashMap<>(); |
||||
row1.put("address", "上海"); |
||||
row1.put("name", "张三"); |
||||
row1.put("phone", "110"); |
||||
row1.put("age", "18"); |
||||
row1.put("height", "170"); |
||||
Map<String, Object> row2 = new HashMap<>(); |
||||
row2.put("address", "上海"); |
||||
row2.put("name", "李四"); |
||||
row2.put("phone", "120"); |
||||
row2.put("age", "19"); |
||||
row2.put("height", "173"); |
||||
Map<String, Object> row3 = new HashMap<>(); |
||||
row3.put("address", "北京"); |
||||
row3.put("name", "王五"); |
||||
row3.put("phone", "119"); |
||||
row3.put("age", "22"); |
||||
row3.put("height", "175"); |
||||
Map<String, Object> row4 = new HashMap<>(); |
||||
row4.put("address", "北京"); |
||||
row4.put("name", "赵六"); |
||||
row4.put("phone", "114"); |
||||
row4.put("age", "30"); |
||||
row4.put("height", "180"); |
||||
DATA = ListUtils.newArrayList(row1, row2, row3, row4); |
||||
Map<String, String> alias = new HashMap<>(); |
||||
alias.put("name", "姓名"); |
||||
alias.put("phone", "手机号"); |
||||
alias.put("address", "地址"); |
||||
alias.put("age", "年龄"); |
||||
alias.put("height", "身高"); |
||||
ALIAS = alias; |
||||
} |
||||
|
||||
@Test |
||||
void testExportPivot() { |
||||
Pair<List<List<String>>, List<List<Object>>> headAndData = PivotUtils.getHeadAndData(ROW_FIELDS, COLUMN_FIELDS, AGG_FIELDS, DATA); |
||||
write(headAndData); |
||||
} |
||||
|
||||
@Test |
||||
void testExportPivotHaveAlias() { |
||||
Pair<List<List<String>>, List<List<Object>>> headAndData = PivotUtils.getHeadAndData(ROW_FIELDS, COLUMN_FIELDS, AGG_FIELDS, ALIAS, DATA); |
||||
write(headAndData); |
||||
} |
||||
|
||||
private void write(Pair<List<List<String>>, List<List<Object>>> headAndData) { |
||||
ExcelWriter writer = EasyExcelFactory.write(EXPORT_FILE_PATH).build(); |
||||
WriteSheet sheet = EasyExcelFactory.writerSheet(SHEET_NAME) |
||||
.head(headAndData.getKey()) |
||||
.build(); |
||||
writer.write(headAndData.getValue(), sheet); |
||||
writer.finish(); |
||||
} |
||||
} |
Loading…
Reference in new issue