Просто перебор всех элементов и пропуск дубликатов (выполняется автоматически HashSet). Существуют лучшие способы объединения строк, но для простоты:
HashSet<String> result = new HashSet<String>();
for (String a : finalMap.get(0)) {
for (String b : finalMap.get(1)) {
for (String c : finalMap.get(2)) {
for (String d : finalMap.get(3)) {
result.add(a + b + c + d);
}
}
}
}
System.out.println(result);
Вывод должен быть как
[a3b2c1d1, a1b3c1d1, a1b1c1d1, a1b2c2d1, a4b1c2d1, a4b3c2d1, a1b2c1d1, a2b1c2d1, a2b2c2d1, a3b3c2d1, a1b1c2d1, a1b3c2d1, a2b3c2d1, a3b3c1d1, a2b2c1d1, a4b1c1d1, a4b3c1d1, a4b2c1d1, a3b1c2d1, a2b3c1d1, a3b1c1d1, a4b2c2d1, a2b1c1d1, a3b2c2d1]
Однако, если вы еще не знаете общее количество списков или они могут отличаться, вы можете использовать рекурсивный подход
void generate(HashSet<String> resultList, String resultString,
int listNum, HashMap<Integer, ArrayList<String>> data) {
if (listNum == 0) {
// start: begin a new resultString
for (int i = 0; i < data.get(listNum).size(); i++) {
generate(resultList, data.get(listNum).get(i), listNum + 1,
data);
}
} else if (listNum == data.size() - 1) {
// end: store completed resultStrings
for (int i = 0; i < data.get(listNum).size(); i++) {
resultList.add(resultString + data.get(listNum).get(i));
}
} else {
// middlepart: append current string to given resultString
for (int i = 0; i < data.get(listNum).size(); i++) {
generate(resultList, resultString + data.get(listNum).get(i),
listNum + 1, data);
}
}
}
называется следующим образом:
HashSet<String> result = new HashSet<String>();
generate(result2, null, 0, finalMap);
System.out.println(result);
Вывод также должен быть как
[a3b2c1d1, a1b3c1d1, a1b1c1d1, a1b2c2d1, a4b1c2d1, a4b3c2d1, a1b2c1d1, a2b1c2d1, a2b2c2d1, a3b3c2d1, a1b1c2d1, a1b3c2d1, a2b3c2d1, a3b3c1d1, a2b2c1d1, a4b1c1d1, a4b3c1d1, a4b2c1d1, a3b1c2d1, a2b3c1d1, a3b1c1d1, a4b2c2d1, a2b1c1d1, a3b2c2d1]