Динамически создавать циклы для итерации по списку списков


У меня есть List из List<String>, которые я получаю из внешнего вызова метода API:

List<List<String>> outerList
Я должен создавать уникальные комбинации клавиш, объединяя строки из каждого списка в том же порядке, в котором они находятся во внешнем списке.

Пример: если внешний список имеет 2 внутренних списка, скажем list1: {"A", "B"} и list2: {"C", "D"}. Тогда возможными уникальными комбинациями будут AC, AD, BC и BD.

Но проблема в том, что размер outerList динамический, он может содержать любое количество внутренних списков. Если внутренний список числа фиксированы, тогда я могу писать для петель и создавать комбинации. Я думаю в направлении использования отражений, рекурсии и т. д., Но до сих пор не смог решить эту проблему.
public static void main(String[] args) {

    List<List<String>> outerList = new ArrayList<List<String>>();
    List<String> list1 = new ArrayList<String>();
    list1.add("A");
    list1.add("B");
    List<String> list2 = new ArrayList<String>();

    list2.add("C");
    list2.add("D");
    outerList.add(list1);

    outerList.add(list2);

    for(String s1: list1) {
        for(String s2: list2) {
            System.out.println(s1+s2);
        }
    }
}

Здесь outerList имеет 2 внутренних списка, поэтому я создал 2 для циклов явно для итерации и конкатенации. Но в реальном времени внешний список может иметь любое количество внутренних списков, как сделать динамический цикл через все внутренние циклы и объединить их?

2 2

2 ответа:

Этот код работает для меня:

public class Test
{  

    public static void generate(LinkedList<LinkedList<String>> outerList, String outPut) {
        LinkedList<String> list = outerList.get(0);

        for(String str : list) {
            LinkedList<LinkedList<String>> newOuter = new LinkedList<LinkedList<String>>(outerList);
            newOuter.remove(list);

            if(outerList.size() > 1) {
                generate(newOuter, outPut+str);
             } else {
               System.out.println(outPut+str);
             }
        }
    }

    public static void main(String[] args) 
    {
        LinkedList<LinkedList<String>> outerList = new LinkedList<LinkedList<String>>();

        LinkedList<String> list1 = new LinkedList<String>();
        LinkedList<String> list2 = new LinkedList<String>();

        list1.add("A");
        list1.add("B");

        list2.add("C");
        list2.add("D");

        outerList.add(list1);
        outerList.add(list2);

        Test.generate(outerList, "");
    }      
}

Вывод:

AC
AD
БК
BD

Выборка данных с достаточной вариацией, чтобы продемонстрировать проблему:

    List<List<String>> outerList = new ArrayList<List<String>>();

    List<String> innerList1 = new ArrayList<String>();
    innerList1.add("A");
    innerList1.add("B");
    outerList.add(innerList1);

    List<String> innerList2 = new ArrayList<String>();
    innerList2.add("X");
    innerList2.add("Y");
    innerList2.add("Z");
    outerList.add(innerList2);

    List<String> innerList3 = new ArrayList<String>();
    innerList3.add("P");
    innerList3.add("Q");
    innerList3.add("R");
    outerList.add(innerList3);

Хранить массив счетчиков:

    int[] positions = new int[outerList.size()];

    boolean another = true;
    while (another) {
        for (int n = 0; n < outerList.size(); n++) {
            System.out.print(outerList.get(n).get(positions[n]));
        }
        System.out.println();

        another = false;
        for (int c = 0; c < outerList.size(); c++) {
            positions[c]++;
            if (positions[c] < outerList.get(c).size()) {
                another = true;
                break;
            }
            positions[c] = 0;
        }
    }

Каждый раз вокруг основного цикла я печатаю по одному элементу из каждого внутреннего списка. Затем я выдвигаю счетчики, начиная с первого. Если это не выходит за пределы первого внутреннего списка, мы готовы напечатать снова. Но если это так, я ставлю этот счетчик на ноль и пытаюсь продвинуть второй, и так далее. Если они все обернутся к нулю, то пора завязывать.

Это на самом деле это похоже на подсчет, за исключением того, что у каждого столбца есть своя "база" (вместо того, чтобы все они были базовыми десятью или двумя или чем-то еще).