package com.visy.util;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import java.util.*;
/**
* @author visy.wang
* @date 2022/1/26 9:39
*/
public class MapUtil {
/**
* Map拆分 (指定分组大小)
* @param map Map
* @param chunkSize 每个分组的大小 (>=1)
* @param <K> Key
* @param <V> Value
* @return 子Map列表
*/
public static <K,V> List<Map<K,V>> splitByChunkSize(Map<K,V> map, int chunkSize){
if(Objects.isNull(map) || map.isEmpty() || chunkSize<1){
//空map或者分组大小<1,无法拆分
return Collections.emptyList();
}
int mapSize = map.size(); //键值对总数
int groupSize = mapSize/chunkSize + (mapSize%chunkSize==0?0:1); //计算分组个数
List<Map<K,V>> list = Lists.newArrayListWithCapacity(groupSize); //子Map列表
if(chunkSize >= mapSize){ //只能分1组的情况
list.add(map);
return list;
}
int count = 0; //每个分组的组内计数
Map<K,V> subMap = Maps.newHashMapWithExpectedSize(chunkSize); //子Map
for (Map.Entry<K, V> entry : map.entrySet()) {
if (count < chunkSize) {
//给每个分组放chunkSize个键值对,最后一个分组可能会装不满
subMap.put(entry.getKey(), entry.getValue());
count++; //组内计数+1
} else {
//结束上一个分组
list.add(subMap); //当前分组装满了->加入列表
//开始下一个分组
subMap = Maps.newHashMapWithExpectedSize(chunkSize); //新的分组
subMap.put(entry.getKey(), entry.getValue()); //添加当前键值对
count = 1; //组内计数重置为1
}
}
list.add(subMap); //添加最后一个分组
return list;
}
/**
* Map拆分(指定分组个数)
* @param map Map
* @param groupSize 分组个数 (>=1)
* @param <K> Key
* @param <V> Value
* @return 子Map列表
*/
public static <K,V> List<Map<K,V>> splitByGroupSize(Map<K,V> map, int groupSize){
if(Objects.isNull(map) || map.isEmpty() || groupSize<1){
//空map或者分组数<1,无法拆分
return Collections.emptyList();
}
List<Map<K,V>> list = Lists.newArrayListWithCapacity(groupSize);
if(groupSize == 1){ //只有1个分组的情况
list.add(map);
return list;
}
int mapSize = map.size(); //键值对总数
int chunkIndex = 0; //当前分组的下标,[0, groupSize-1]
int restCount = mapSize % groupSize; //平均后剩余的键值对数
int chunkSize0 = mapSize / groupSize; //每个分组键值对数量
int chunkSize1 = chunkSize0 + 1; //多分一个
int chunkSize = chunkIndex<restCount ? chunkSize1 : chunkSize0; //实际每组的大小(前面的部分分组可能会多分1个)
int count = 0; //每个分组的组内计数
Map<K,V> subMap = Maps.newHashMapWithExpectedSize(chunkSize);//子Map
for (Map.Entry<K, V> entry : map.entrySet()) {
if(count < chunkSize){
//每个分组按实际分组大小(chunkSize)加入键值对
subMap.put(entry.getKey(), entry.getValue());
count ++; //组内计数+1
}else{
//结束上一个分组
list.add(subMap); //当前分组装满了->加入列表
chunkIndex ++; //分组个数+1
//开始下一个分组
chunkSize = chunkIndex<restCount ? chunkSize1 : chunkSize0; //重新计算分组大小
subMap = Maps.newHashMapWithExpectedSize(chunkSize); //新的分组
subMap.put(entry.getKey(), entry.getValue()); //添加当前键值对
count = 1; //组内计数重置为1
}
}
list.add(subMap); //添加最后一个分组
return list;
}
//测试
public static void main(String[] args) {
Map<String,String> map = new HashMap<>();
map.put("a", "1");
map.put("b", "2");
map.put("c", "3");
map.put("d", "4");
map.put("e", "5");
map.put("f", "6");
map.put("g", "7");
System.out.println("splitByChunkSize: " + splitByChunkSize(map, 3));
System.out.println("splitByGroupSize: " + splitByGroupSize(map, 3));
}
}
输出:
splitByChunkSize: [{a=1, b=2, c=3}, {d=4, e=5, f=6}, {g=7}]
splitByGroupSize: [{a=1, b=2, c=3}, {d=4, e=5}, {f=6, g=7}]