天天看点

使用递归实现不定层多重循环(二维数组中各维度元素组合)

文章目录

    • 1. 业务需求描述
    • 2. 方法一
    • 3. 方法二
    • 4. 方法比较

1. 业务需求描述

比如描述狗的品种有如下多个角度:

使用递归实现不定层多重循环(二维数组中各维度元素组合)

我们可以将其表示为一个二维数组的形式:

String[][] dogStyle = { { "小型", "中型", "大型" }, { "家庭犬", "玩具犬", "工作犬", "牧羊犬" } ,{"聪明", "友善"}};
           

我们现在的需求是: 需要从各个组合角度统计狗的品种的数量,……等等,不对,这是后续的需求,现在需要知道各个角度所有可能的组合,如:

小型-家庭犬-聪明
小型-家庭犬-友善
小型-玩具犬-聪明
……
大型-牧羊犬-友善
           

很简单啊,一个三层循环搞定,但是问题是:可能有10个维度,那就是10层循环了,或者,我根本不知道需要几层循环,目前客户从3个维度描述了一只狗,以后他可能从N个维度描述一只狗。

好了,需求:从N个维度各抽一个元素进行组合,需要得到所有可能的组合。

感觉这个需求很简单,又不好描述,如果还未表达清楚或者对文章题目有什么好的意见的话(我非常不满意这个题目),非常欢迎下方评论。

2. 方法一

直接拷过去,执行看看效果;打断点,debug看看执行过程。

package com.fukaiit;

public class Test {
	public static void main(String[] args) {
		String[][] dogStyles = { { "小型", "中型", "大型" }, { "家庭犬", "玩具犬", "工作犬", "牧羊犬" }, { "聪明", "友善" } };
		recursion(0, dogStyles, "");// 0表示从第一维开始遍历
	}

	private static void recursion(int index, String[][] dogStyles, String dogStyleCombination) {
		for (int i = 0; i < dogStyles[index].length; i++) {
			String dogStyle = dogStyles[index][i];// 获取到当前遍历到的某个具体的元素
			String tempDSC = dogStyleCombination + "  " + dogStyle;// dogStyleCombination表示元素的组合,这里换成List也是可以的,不过注意要clone
			if (index + 1 == dogStyles.length) {// 如果到了最后一维,直接输出
				System.out.println(tempDSC);
			} else {// 如果还没到最后一维,带着当前组合的部分进行下一维
				recursion(index + 1, dogStyles, tempDSC);
			}
		}
	}
}
           

执行效果:

使用递归实现不定层多重循环(二维数组中各维度元素组合)

也可以把二维数组换成HashMap啥的,如:

HashMap<String, List<String>> dogStyles=new HashMap<String, List<String>>();
           

数据举例:

{
    size: ["小型", "中型", "大型"],
    function: ["家庭犬", "玩具犬", "工作犬", "牧羊犬"],
    trait: ["聪明", "友善"]
}
           

输出的时候也可以输出成一个

List<List<String>>

本文为了使代码尽量清晰点,使用了二维数组和字符串拼接这种最简洁的方式。

3. 方法二

同样,先上代码:

package com.fukaiit;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Test {
	public static void main(String[] args) {
		String[][] dogStyles = { { "小型", "中型", "大型" }, { "家庭犬", "玩具犬", "工作犬", "牧羊犬" }, { "聪明", "友善" } };
		List<String> result = recursion(dogStyles, Arrays.asList(dogStyles[0]), Arrays.asList(dogStyles[1]), 1);//这里为什么传1呢,因为0相当于已经是既定的了,从第二维开始遍历
		for (String str : result) {
			System.out.println(str);
		}
	}

	private static List<String> recursion(String[][] dogStyles, List<String> dogStyleCombination, List<String> currentlist, int index) {//参数可以简化,我先不管了
		List<String> tempList = new ArrayList<>();
		for (int i = 0; i < dogStyleCombination.size(); i++) {//dogStyleCombination是已经组合好的部分
			for (int k = 0; k < currentlist.size(); k++) {//currentlist是当前需要组合上去的部分
				tempList.add(dogStyleCombination.get(i) + "  " + currentlist.get(k));
			}
		}
		if (index + 1 == dogStyles.length) {// 如果到了最后一维,直接返回
			return tempList;
		} else {// 如果还没到最后一维,带着当前组合的部分进行下一维
			return recursion(dogStyles, tempList, Arrays.asList(dogStyles[index + 1]), index + 1);
		}
	}
}
           

方法2的逻辑:将第一维各元素和第二维各元素组合,组合好之后,去检查有没有下一维:如果有的话,拿着已组合好的部分(其实相当于单纯的一个维度,只是行数更多)和下一维各元素再去组合,直到最后一维,则直接返回。

4. 方法比较

简单比较一下两个方法:

  1. 相同点

    (1)递归的思想和处理都是一样的

    (2)两个方法能互相替代实现完全相同的业务需求

  2. 不同点

    (1)方法1的递归更简洁,递归方法中只有一层for循环,方法2中有两层for循环,当二维数组.length<=1的时候稍有点问题,需要特殊处理一下。

    (2)方法2的思路更清晰,代码可读性更强