Динамически создавать циклы для итерации по списку списков
У меня есть 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 ответа:
Этот код работает для меня:
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; } }
Каждый раз вокруг основного цикла я печатаю по одному элементу из каждого внутреннего списка. Затем я выдвигаю счетчики, начиная с первого. Если это не выходит за пределы первого внутреннего списка, мы готовы напечатать снова. Но если это так, я ставлю этот счетчик на ноль и пытаюсь продвинуть второй, и так далее. Если они все обернутся к нулю, то пора завязывать.
Это на самом деле это похоже на подсчет, за исключением того, что у каждого столбца есть своя "база" (вместо того, чтобы все они были базовыми десятью или двумя или чем-то еще).