(ps. I just rewrote the question as I thought it was dealing with permutations, but it is actually dealing with combinations.)
Consider more specifically a Map<String, List<WordGroupAndScore> baseMap
, with:
private static class WordGroupAndScore {
public final WordGroup wordGroup;
public final int score;
public WordGroupAndScore(final WordGroup wordGroup, final int score) {
this.wordGroup = wordGroup;
this.score = score;
}
}
The baseMap.size()
is variable, meaning that there can be any number of String
s in the map. Also for every element in baseMap
, baseMap.get(i).size()
is variable. But the baseMap
cannot contain empty lists.
Now I am trying to find all possible combinations. The code itself is for checking data in invoices, not always all data is available on an invoice, hence the variable amount of baseMap.size()
. And the list per element in baseMap
is variable, because the amount of data found depends on which invoice it is.
(Example data does not correspond one to one in the example, as in reality it is WordGroupAndScore
, but I'll use String
s or BigDecimal
s to represent the data in the example)
Example data of baseMap
(values and key pairs) strictly (A
and List<B>
pairs):
("invoiceNumber", ["0001", "0002"])
("invoiceDate", ["2013-10-07"])
("priceExclVAT, [new BigDecimal("10.00")])
("highVAT, [new BigDecimal("2.10")])
("priceInclVAT, [new BigDecimal("12.10"), new BigDecimal("14.10")])
I want to generate all possible combinations of the data.
Example output, one ("first") combination (values and single key pairs) strictly (A
and B
pairs):
("invoiceNumber", "0001")
("invoiceDate", "2013-10-07"])
("priceExclVAT, new BigDecimal("10.00"))
("highVAT, new BigDecimal("2.10"))
("priceInclVAT, new BigDecimal("12.10"))
Example output, one ("last") combination (values and single key pairs) strictly (A
and B
pairs):
("invoiceNumber", "0002")
("invoiceDate", "2013-10-07")
("priceExclVAT, new BigDecimal("10.00"))
("highVAT, new BigDecimal("2.10"))
("priceInclVAT, new BigDecimal("14.10"))
So somehow I need to iterate over the full baseMap
, remember/create all combinations based on every baseMap.get(i).size()
, but I am pretty much lost where to start. Biggest problem is that: how would I remember the combinations, because my baseMap
is of variable size. If it would not have been variable, then I could've done it much easier.
I hope the question is clear enough.
EDIT: Added one of my tries, which doesn't work.
//Assumes that wordGroupsAndScores does not get changed during the process
private void processWordGroupAndScores(TemplateBean template) {
System.out.println();
System.out.println("--wordGroupsAndScores--");
for (Map.Entry<String, List<WordGroupAndScore>> entry : wordGroupsAndScores.entrySet()) {
System.out.println("Attribute = " + entry.getKey());
for (WordGroupAndScore wordGroupAndScore : entry.getValue()) {
System.out.println("WordGroupAndScore = " + wordGroupAndScore);
}
System.out.println(";");
}
System.out.println();
//create all possible unfinishedinvoices from wordgroupandscores
int[] indices = new int[wordGroupsAndScores.keySet().size()];
for (int index = 0; index < indices.length; index++) {
indices[index] = 0;
}
String[] keyLocation = new String[wordGroupsAndScores.keySet().size()];
int j = 0;
for (String key : wordGroupsAndScores.keySet()) {
keyLocation[j] = key;
j++;
}
processWordGroupAndScoresRecursive(indices, keyLocation, template);
}
private void processWordGroupAndScoresRecursive(int[] indices, String[] keyLocation, TemplateBean template) {
processWordGroupAndScoresWithIndices(indices, keyLocation, template);
boolean changedIndices = false;
for (int index = indices.length - 1; index >= 0; index--) {
if (indices[index] < wordGroupsAndScores.get(keyLocation[index]).size() - 1) {
indices[index]++;
changedIndices = true;
break;
}
}
if (changedIndices) {
processWordGroupAndScoresRecursive(indices, keyLocation, template);
}
}
private void processWordGroupAndScoresWithIndices(int[] indices, String[] keyLocation, TemplateBean template) {
System.out.println();
System.out.println("--Generated combination--");
UnfinishedInvoice unfinishedInvoice = new UnfinishedInvoice();
for (int index = 0; index < indices.length; index++) {
String key = keyLocation[index];
WordGroupAndScore wordGroupAndScore = wordGroupsAndScores.get(key).get(indices[index]);
System.out.println("Attribute = " + key);
System.out.println("WordGroupAndScore = " + wordGroupAndScore);
System.out.println(";");
setUnfinishedInvoiceAttribute(key, unfinishedInvoice, Utils.joinWordGroup(wordGroupAndScore.wordGroup, " "), wordGroupAndScore.score);
}
System.out.println();
unfinishedInvoice.verify();
if (templateMap.containsKey(template)) {
templateMap.get(template).add(unfinishedInvoice);
}
else {
List<UnfinishedInvoice> list = new ArrayList<>();
list.add(unfinishedInvoice);
templateMap.put(template, list);
}
}
Let's take a more clear look at what it produces, let us only work with the indices, and not with real data anymore.
Let's say this is the input: [1, 1, 2, 1, 0]
. With it being the characterization of a map as a list, with as elements the index of the element in the lists inside the original map. We start by the combination where the last elements from the map is being taken.
With my failing code we get as output:
[1, 1, 2, 1, 0]
[1, 1, 2, 0, 0]
[1, 1, 1, 0, 0]
[1, 1, 0, 0, 0]
[1, 0, 0, 0, 0]
[0, 0, 0, 0, 0]
This is not correct as there are a lot of values missing, for example [0, 0, 0, 1, 0]
is missing.
What is going wrong here?