背景
业务需求需要图片根据DMP多个类型动态词包内容生成n*n的所有组合图片,这就需要先组合出所有词包的可能,且词包类型数量不限制,总组合数可以控制。本文重点记录n层for循环java代码实现。
实现1: for循环递归
通过递归方式,把n阶循环转变到2层for循环
@Test
public void recursionFor() {
Map<Integer, Set<Long>> map = new HashMap<>();
Long[] l1 = {1L, 2L};
Long[] l2 = {3L, 4L,5L};
Long[] l3 = {6L, 7L};
map.put(1, new HashSet<>(Arrays.asList(l1)));
map.put(2, new HashSet<>(Arrays.asList(l2)));
map.put(3, new HashSet<>(Arrays.asList(l3)));
List<Map<Integer, Long>> xx = getAllTagTypeAndTagIdMatch(map);
System.out.println(xx);
}
/**
* 递归获取所有的组合
* @param tagTypeTagIdMap key为词包类型,value为词包内容集合
* @return 按词包类型返回所有的组合内容
*/
private List<Map<Integer, Long>> getAllTagTypeAndTagIdMatch(Map<Integer, Set<Long>> tagTypeTagIdMap){
if (tagTypeTagIdMap.size() == 1) {
List<Map<Integer, Long>> result = new ArrayList<>();
for (Map.Entry<Integer, Set<Long>> entry : tagTypeTagIdMap.entrySet()) {
for (Long tagID : entry.getValue()) {
Map<Integer, Long> map = new HashMap<>();
map.put(entry.getKey(), tagID);
result.add(map);
}
}
return result;
} else if (tagTypeTagIdMap.size() == 2) {
Set<Integer> tagTypeSet = tagTypeTagIdMap.keySet();
Iterator<Integer> iterator = tagTypeSet.iterator();
Integer tagType1 = iterator.next();
Integer tagType2 = iterator.next();
Set<Long> tagIdSet1 = tagTypeTagIdMap.get(tagType1);
Set<Long> tagIdSet2 = tagTypeTagIdMap.get(tagType2);
List<Map<Integer, Long>> result = new ArrayList<>();
for (Long tagId1 : tagIdSet1) {
for (Long tagId2 : tagIdSet2) {
Map<Integer, Long> map = new HashMap<>();
map.put(tagType1, tagId1);
map.put(tagType2, tagId2);
result.add(map);
}
}
return result;
} else {
List<Map<Integer, Long>> result = new ArrayList<>();
Set<Integer> tagTypeSet = tagTypeTagIdMap.keySet();
Iterator<Integer> iterator = tagTypeSet.iterator();
if (iterator.hasNext()) {
Integer tagType1 = iterator.next();
Set<Long> tagIdSet = tagTypeTagIdMap.get(tagType1);
Map<Integer, Set<Long>> newTagTypeTagIdMap = new HashMap<>();
newTagTypeTagIdMap.putAll(tagTypeTagIdMap);
newTagTypeTagIdMap.remove(tagType1);
List<Map<Integer, Long>> oneResult = getAllTagTypeAndTagIdMatch(newTagTypeTagIdMap);
for (Map<Integer, Long> oneMap : oneResult) {
for (Long tagId : tagIdSet) {
Map<Integer, Long> map = new HashMap<>();
map.putAll(oneMap);
map.put(tagType1, tagId);
result.add(map);
}
}
}
return result;
}
}
实现2 双数组
双数组记录每层数(即每个词包类型的内容数),类似时分秒指针,从词包最大内容值和最外层一点点减小组合。
@Test
public void doubleArrayFor() {
Map<Integer, List<Long>> map = new HashMap<>();
Long[] l1 = {1L, 2L};
Long[] l2 = {3L, 4L, 5L};
Long[] l3 = {6L};
map.put(1, Arrays.asList(l1));
map.put(2, Arrays.asList(l2));
map.put(3, Arrays.asList(l3));
List<Map<Integer, List<Long>>> xx = createAllCombination(map);
System.out.println(xx);
}
/**
* 生成所有组合
* @param dmpTagTypeMap
* @return
*/
public List<Map<Integer, List<Long>>> createAllCombination(Map<Integer, List<Long>> dmpTagTypeMap) {
List<Map<Integer, List<Long>>> resultList = new ArrayList<>();
int size = dmpTagTypeMap.size();
if(size <= 0){
return resultList;
}
int[] tree0 = new int[size];
int[] tree1 = new int[size];
int i = 0;
for (Integer dmpTagType : dmpTagTypeMap.keySet()) {
List<Long> longList = dmpTagTypeMap.get(dmpTagType);
tree0[i] = longList.size()-1;
tree1[i] = longList.size()-1;
i++;
}
while (tree0[0] >= 0) {
Map<Integer, List<Long>> result = new HashMap<>(size);
int j = 0;
for (Integer dmpTagType : dmpTagTypeMap.keySet()) {
List value = dmpTagTypeMap.get(dmpTagType);
Long lv = (Long) value.get(tree0[j]);
result.put(dmpTagType,Arrays.asList(lv));
j++;
}
resultList.add(result);
subTree(tree0,tree1,size-1);
}
return resultList;
}
/**
* 确定每次组合取值范围,当最外层遍历到<0时,恢复这层原始值,开始衰减倒数第二层数
* @param tree0 当前每层取值范围,会一直变更
* @param tree1 记录最原始每层数据
* @param subIndex 当前层偏移值
*/
private static void subTree(int[] tree0,int[] tree1,int subIndex){
if (subIndex>0){
if (--tree0[subIndex]<0) {
tree0[subIndex] = tree1[subIndex];
subTree(tree0, tree1, --subIndex);
}
}else if (subIndex == 0) --tree0[0];
}
本文探讨了如何在Java中实现n层for循环,以满足动态词包组合生成的需求。介绍了两种方法:一是通过递归将n阶循环转化为2层for循环;二是使用双数组,如同时针和分针,从最大值开始逐步减少组合。

743

被折叠的 条评论
为什么被折叠?



