I have a map which contains variable length string list. eg
Map<String, List<String> map = new HashMap<>();
map.put("key", "key1, key2);
map.put("name", "name1, name2, name3");
map.put("code", "code1, code2");
This will give 12 different permutations. The below code does that job
List<String> values = new ArrayList<>();
for (int i = 0; i < map.get("key").size(); i++) {
values.add(map.get("key").get(i));
for (int j = 0; j < map.get("name").size(); j++) {
values.add(map.get("name").get(j));
for (int k = 0; k < map.get("code").size(); k++) {
values.add(map.get("code").get(k));
}
}
}
Expected output:
"key1", "name1", "code1",
"key1", "name1", "code2",
"key1", "name2", "code1",
"key1", "name2", "code2",
"key1", "name3", "code1",
"key1", "name3", "code2",
"key2", "name1", "code1",
"key2", "name1", "code2",
"key2", "name2", "code1",
"key2", "name2", "code2",
"key2", "name3", "code1",
"key2", "name3", "code2"
But the problem is this is hard coded with 3 for loops, but what I expect is to support for any number of variables. Prompt help is much appreciated.
Following snippet solves this problem.
protected static void traverseParam(Map<String, List<String>> paramLists, int level, Map<String, String> paramMap) {
if (level == paramLists.size()) {
//contains of all combinations
System.out.println(StringUtils.join(paramMap.values(), ", "));
} else {
String paramKey = (String) paramLists.keySet().toArray()[level];
List<String> paramValues = (List<String>) paramLists.values().toArray()[level];
for (String paramValue : paramValues) {
paramMap.put(paramKey, paramValue);
//Recursively calls until all params are processed
traverseParam(paramLists, level + 1, paramMap);
}
}
}
Now call this method like below.
Map<String, List<String> map = new HashMap<>();
map.put("key", "key1, key2);
map.put("name", "name1, name2, name3");
map.put("code", "code1, code2");
//Start with 1st parameter, and pass
//an empty LinkedHashMap and all entries will be added to this map.
traverseParam(map, 0, new LinkedHashMap<String, String>());
I provided below a sample solution, using recursion.
In the example we have 3 lists, with rep. 3,4,4 elements; the program prints all 3*4*4=48 combinations of elements.
Starting with an empty combination (an empty list), at each step(i) we take N=list(i).size() copies of the current tuple, add value(j)=list(i)[j] to the j-th new tuple (for j=1..N), and recurse. When i=list.size, then the tuple is complete and we can use it (eg. print it out). (lists can be copied using the constructor).
package sample;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import java.util.function.Consumer;
public class SampleCombinations {
public static void main(String[] args) {
Map<String, List<String>> map = new TreeMap<>();
map.put("x", Arrays.asList("a", "b", "c"));
map.put("y", Arrays.asList("0", "1", "2", "3"));
map.put("z", Arrays.asList("!", "-", "=", "%"));
ArrayList<Entry<String, List<String>>> entries = new ArrayList<>(map.entrySet());
System.out.println(entries);
printCombinations(entries);
}
private static void printCombinations(List<Entry<String, List<String>>> entries) {
Consumer<List<String>> cons = list -> System.out.println(list);
generateComb(entries, cons, 0, new LinkedList<>());
}
private static void generateComb(List<Entry<String, List<String>>> entries,
Consumer<List<String>> consumer, int index, List<String> currentTuple) {
/*
* terminal condition: if i==entries.size the tuple is complete
* consume it and return
*/
if(index==entries.size()) {
consumer.accept(currentTuple);
}
else {
/*
* get all elements from the i-th list, generate N new tuples and recurse
*/
List<String> elems = entries.get(index).getValue();
for (String elem:elems) {
// copy the current tuple
LinkedList<String> newTuple = new LinkedList<>(currentTuple);
newTuple.add(elem);
generateComb(entries, consumer, index+1, newTuple);
}
}
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.