【问题标题】:Create multiple arrays from a given string array从给定的字符串数组创建多个数组
【发布时间】:2021-04-20 15:13:05
【问题描述】:

我有一个唯一字符串数组,我需要从中创建所有可能的具有相同长度的数组。

String[] str = {"Belgium", "France", "Germany"};

目标是创建一个数组列表,其中每个索引处都有上述数组中的每个可能值,

[Belgium, Belgium, Belgium]
[Belgium, Belgium, France]
[Belgium, Belgium, Germany]
[Belgium, France, Belgium]
[Belgium, France, France]
[Belgium, France, Germany]
[Belgium, Germany, Belgium]
[Belgium, Germany, France]
[Belgium, Germany, Germany]
[France, Belgium, Belgium]

....

[Germany, Germany, France]
[Germany, Germany, Germany]

我创建这个的代码看起来像

static List<String[]> getAllAllocations(String[] input){
    List<String[]> result = new ArrayList<>();
    if(input.length == 2){
        for(int i = 0; i < 2; i++){
            for(int j = 0; j < 2; j++){
                result.add(new String[]{input[i], input[j]});
            } 
        }
    }
    else if(input.length == 3){
        for(int i = 0; i < 3; i++){
            for(int j = 0; j < 3; j++){
                for(int k = 0; k < 3; k++){
                    result.add(new String[]{input[i], input[j], input[k]});
                }
            } 
        }
    }
    else if(input.length == 4){
        for(int i = 0; i < 4; i++){
            for(int j = 0; j < 4; j++){
                for(int k = 0; k < 4; k++){
                    for(int m = 0; m < 4; m++){
                        result.add(new String[]{input[i], input[j], input[k], input[m]});
                    }
                }
            } 
        }
    }
    //else if(input.length == 5) similar code with 5 for loops
    //else if(input.length == 6) similar code with 6 for loops
    //else if(input.length == 7) similar code with 7 for loops
    //else if(input.length == 8) similar code with 8 for loops
    return result;
}

数组将具有 2 到 8 之间的可变长度。如何动态创建 for 循环,而不是链接 if-else 检查或以比我上面所做的更优雅的方式执行此操作?

【问题讨论】:

  • 这里的神奇词是递归!
  • @Rocco 我已经尝试过递归,但这很困难,而且我在将字符串添加到现有数组时遇到了问题。我将不胜感激更多输入如何使用递归来解决这个问题

标签: java arrays for-loop


【解决方案1】:

递归解

public static List<String[]> getAllAllocations(String[] input) {
    List<String[]> result=new ArrayList<String[]>();
    getAllAllocations(result, input, new String[input.length], 0);
    return result;
}

public static void getAllAllocations(List<String[]> result, String[] input, String[] current, int depth) {
    if (depth>=input.length) {
        result.add(current.clone());
    } else {
        for (int i=0;i<input.length;i++) {
            current[depth]=input[i];
            getAllAllocations(result, input, current, depth+1);
        }
    }
}

迭代解决方案

public static List<String[]> getAllAllocations2(String[] input) {
    List<String[]> result=new ArrayList<String[]>();
    
    int[] counters=new int[input.length];
    
    boolean done=false;
    while (!done) {
        
        String[] comb=new String[input.length];
        for (int i=0;i<comb.length;i++) {
            comb[i]=input[counters[i]];
        }
        result.add(comb);

        done=true;
        for (int i=0;i<counters.length;i++) {
            counters[i]++;
            if (counters[i]>=input.length) {
                counters[i]=0;
            } else {
                done=false;
                break;
            }
        }
    }
    
    return result;
}

【讨论】:

  • 非常感谢。我没有完全理解发生了什么,特别是在第二种方法中,但用不同的输入对其进行了测试,这可以按需要工作。再次感谢您。
  • @Biscuit 第二种方法是递归生成组合,通过旋转当前数组中的输入元素。每一级递归负责旋转数组的深度元素,当到达最后一级时,组合完成并添加到结果中。由于当前数组是可变的,因此必须克隆它以避免对结果产生副作用。
  • @Biscuit 我还添加了一个迭代解决方案,但在我看来,在这种情况下递归更加模糊
  • Rocco 在递归方法中使用的具体术语称为回溯。它是一种通常用于基于组合/排列的问题的算法。看看这篇文章——geeksforgeeks.org/backtracking-introduction
  • 我想我开始明白它是如何工作的了。再次感谢其他方法 Rocco 和链接@Tim Tong
【解决方案2】:

您可以使用mapreduce 方法:

  1. map - 首先准备数组列表List&lt;String[]&gt;。三个元素的数组变成了三个单例数组列表:

    list1: [[Belgium], [France], [Germany]]
    list2: [[Belgium], [France], [Germany]]
    list3: [[Belgium], [France], [Germany]]
    
  2. reduce - 然后依次将这些列表一一相乘,得到笛卡尔积。三个列表的两个减少步骤:

    list1: [[Belgium], [France], [Germany]]
    list2: [[Belgium], [France], [Germany]]
    ------
     sum1: [[Belgium, Belgium], [Belgium, France], ..., [Germany, Germany]]
    
     sum1: [[Belgium, Belgium], [Belgium, France], ..., [Germany, Germany]]
    list3: [[Belgium], [France], [Germany]]
    ------
    total: [[Belgium, Belgium, Belgium], [Belgium, Belgium, France], ...]
    

Try it online!

public static void main(String[] args) {
    String[] str = {"Belgium", "France", "Germany"};
    cartesianProduct(str).forEach(arr->System.out.println(Arrays.toString(arr)));
}
static List<String[]> cartesianProduct(String[] input) {
    return IntStream.range(0, input.length)
            // Stream<List<String[]>>
            .mapToObj(i -> Arrays.stream(input)
                    .map(str -> new String[]{str})
                    .collect(Collectors.toList()))
            // stream of lists to a single list
            .reduce((list1, list2) -> list1.stream()
                    .flatMap(arr1 -> list2.stream()
                            .map(arr2 -> Stream.of(arr1, arr2)
                                    .flatMap(Arrays::stream)
                                    .toArray(String[]::new)))
                    .collect(Collectors.toList()))
            .orElse(Collections.emptyList());
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-10
    相关资源
    最近更新 更多