1

I have a map which contains variable length string list. e.g

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.

1
  • 1
    This code isn't generating permutations. What do you want/expect to be in the values map after it's done? Commented Nov 24, 2019 at 19:24

2 Answers 2

1

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>());
Sign up to request clarification or add additional context in comments.

Comments

0

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);
      }
    }
  }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.