需求描述:
根据给定的每个字段的所有值进行排列组合得到一个唯一条件的实体对象。
比如:
Model中有A\B\C三个字段:
- A字段可能的值是1,2,3
- B字段可能的值是4,5,6
- C字段可能的值是1,2,5
这个时候需要根据ABC三个字段的值进行重组,得到一个唯一属性的Model。
比如:
- Model1 : A -> 1,B->4,C->1
- Model2 : A -> 1,B->4,C->2
- Model3 : A -> 1,B->4,C->5
- Model4 : A -> 1,B->5,C->1
- …
得到所有的可能性…
import org.apache.commons.beanutils.BeanUtils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
public class ZhiShuUtils {
/**
* 构建对象
*
* @param ruleMap 规则参数
* @param clazz 转换结果
* @param <T>
* @return
* @throws Exception
*/
public static <T> List<T> builderObject(Map<String, Object> ruleMap, Class<T> clazz) throws Exception {
// 先将Map中的数组大小相乘,得到最终的总条数
Integer maxListSize = 1;
for (Object value : ruleMap.values()) {
if (value instanceof Collection) {
int size = ((Collection)value).size();
maxListSize = maxListSize * size;
}
}
List<Map.Entry<String, Object>> list = new ArrayList<Map.Entry<String, Object>>(ruleMap.entrySet());
// 提前构建参数可能性的对象总数
List<Object> resultMap = new ArrayList<>(maxListSize);
for (int i = 0; i < maxListSize; i++) {
resultMap.add(clazz.newInstance());
}
//迭代
int iterationCount = 1;
for (int i = 0; i < list.size(); i++) {
Map.Entry<String, Object> map = list.get(i);
if (i > 0) {
Map.Entry<String, Object> preMap = list.get(i - 1);
if (preMap.getValue() instanceof List) {
iterationCount = iterationCount * ((List<?>)preMap.getValue()).size();
}
}
putAttr(map.getKey(), map.getValue(), resultMap, iterationCount);
}
return (List<T>)resultMap;
}
/**
* 设置属性
*
* @param key 字段名称
* @param value 字段值
* @param resultMap 实体对象集合
* @param resultIndex 结果下标
*/
private static void putAttr(String key, Object value, List<Object> resultMap, Integer resultIndex) {
int resultSize = resultMap.size();
if (value instanceof List) {
List valueObject = (List)value;
int valueSize = valueObject.size();
for (int i = 0; i < resultSize; i++) {
Object object = resultMap.get(i);
int index = i / resultIndex % valueSize;
Object val = valueObject.get(index);
setProperty(object, key, val);
}
} else {
allEachValue(key, value, resultMap, resultSize);
}
}
/**
* 遍历所有的参数值
*
* @param key
* @param value
* @param resultMap
* @param resultSize
*/
private static void allEachValue(String key, Object value, List<Object> resultMap, int resultSize) {
for (int i = 0; i < resultSize; i++) {
Object object = resultMap.get(i);
setProperty(object, key, value);
}
}
/**
* 设置属性
*
* @param object
* @param key
* @param value
*/
private static void setProperty(Object object, String key, Object value) {
try {
BeanUtils.setProperty(object, key, value);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
调用和验证方式:
@Test
public void test() throws Exception {
// 这里的map的key属性和TestModel中字段需要对应
Map<String, Object> ruleMap = new LinkedHashMap<>();
ruleMap.put("a", Arrays.asList("1", "2", "3"));
ruleMap.put("b", Arrays.asList("4", "5", "6"));
ruleMap.put("c", Arrays.asList("1", "2", "5"));
List<TestModel> ruleList = ZhiShuUtils.builderObject(ruleMap, TestModel.class);
Set<TestModel> arraySet = new HashSet<>();
ruleList.forEach((model) -> {
if (!arraySet.add(model)) {
System.out.println("---->>>存在重复 : " + model);
}
System.out.println(model);
});
}
结果:
TestModel{a='1', b='4', c='1'}
TestModel{a='2', b='4', c='1'}
TestModel{a='3', b='4', c='1'}
TestModel{a='1', b='5', c='1'}
TestModel{a='2', b='5', c='1'}
TestModel{a='3', b='5', c='1'}
TestModel{a='1', b='6', c='1'}
TestModel{a='2', b='6', c='1'}
TestModel{a='3', b='6', c='1'}
TestModel{a='1', b='4', c='2'}
TestModel{a='2', b='4', c='2'}
TestModel{a='3', b='4', c='2'}
TestModel{a='1', b='5', c='2'}
TestModel{a='2', b='5', c='2'}
TestModel{a='3', b='5', c='2'}
TestModel{a='1', b='6', c='2'}
TestModel{a='2', b='6', c='2'}
TestModel{a='3', b='6', c='2'}
TestModel{a='1', b='4', c='5'}
TestModel{a='2', b='4', c='5'}
TestModel{a='3', b='4', c='5'}
TestModel{a='1', b='5', c='5'}
TestModel{a='2', b='5', c='5'}
TestModel{a='3', b='5', c='5'}
TestModel{a='1', b='6', c='5'}
TestModel{a='2', b='6', c='5'}
TestModel{a='3', b='6', c='5'}
具体思路:
- 遍历规则中的每个参数长度大小,得到组合结果总数的长度;
- 提前初始化所有结果对象
- 遍历规则Map中的每个属性填充到结果对象中.
其中第一次遍历的时候是按照顺序循环遍历,后面的话根据上一次的总数累计相乘得到每个值遍历的次数进行循环遍历,有点绕,不过你看打印结果就能够理解了。
也花了蛮多时间,觉得有意思,分享给有需要的人。