Suppose I have several sorted lists of positive numbers, such as:

```
double() a1 = new double(){0.70, 0.20, 0.10};
double() a2 = new double(){0.80, 0.10, 0.05, 0.05};
double() a3 = new double(){0.60, 0.15, 0.14, 0.10, 0.01};
```

I would like to iterate the Cartesian product of these arrays in descending order of entries:

```
0000: Combo(product=3.36e-01, vals=(0.70, 0.80, 0.60), indexes=(0, 0, 0))
0001: Combo(product=9.60e-02, vals=(0.20, 0.80, 0.60), indexes=(1, 0, 0))
0002: Combo(product=8.40e-02, vals=(0.70, 0.80, 0.15), indexes=(0, 0, 1))
0003: Combo(product=7.84e-02, vals=(0.70, 0.80, 0.14), indexes=(0, 0, 2))
0004: Combo(product=5.60e-02, vals=(0.70, 0.80, 0.10), indexes=(0, 0, 3))
0005: Combo(product=4.80e-02, vals=(0.10, 0.80, 0.60), indexes=(2, 0, 0))
...
```

For example, In the above example, the first entry is obvious (because the arrays are sorted) and a combination of the first values: `(0.70, 0.80, 0.60)`

with product `0.70*0.80*0.60 = 3.36e-01`

and corresponding value indexes in arrays `a1, a2, a3`

are `(0, 0, 0)`

, Now the second entry is less obvious, we should change it `0.70`

to `0.20`

? Or `0.60`

to `0.15`

? Or `0.80`

to `0.10`

? The second should be `(0.20, 0.80, 0.60)`

with product `9.60e-02`

indices `(1, 0, 0)`

,

Here is a program in Java to generate / print them: https://repl.it/repls/FilthyGreatRotation (the whole logic is in `printWholeCartesianProduct()`

Method)

This program generates it in lexicographical order and then sorts the entire record by product.

**question**: Is there an easy way to generate the combos in the right order?

**The reason for that**: I do not have the lists in the first place, just iterators over some sorted collections of numbers. Possibly very long, length not known in advance, but it is known that the numbers in each iterator are sorted.

MVCE to play (as in the above link https://repl.it):

```
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.StringJoiner;
import java.util.function.Consumer;
import java.util.stream.Collectors;
public class Main {
public static void main(String() args) {
List
```> data = createData();
printWholeCartesianProduct(data);
}
public static List> createData() {
double() a1 = new double(){0.70, 0.20, 0.10};
double() a2 = new double(){0.80, 0.10, 0.05, 0.05};
double() a3 = new double(){0.60, 0.15, 0.14, 0.10, 0.01};
return createData(a1, a2, a3);
}
public static void printWholeCartesianProduct(List> data) {
final DecimalFormat df = new DecimalFormat("0.00");
// print input data
String matrix = data.stream()
.map(l -> l.stream().map(df::format).collect(Collectors.joining(", ")))
.map(row -> "(" + row + ")")
.collect(Collectors.joining("n"));
System.out.println("Input data:n" + matrix);
// collect combos as they are generated
final List combos = new ArrayList<>();
Consumer callback = indexes -> {
double() v = new double(indexes.length);
double prod = 1;
for (int i = 0; i < indexes.length; i++) {
List col = data.get(i);
int index = indexes(i);
v(i) = col.get(index);
prod *= v(i);
}
combos.add(new Combo(prod, v, indexes.clone()));
};
// generate combos
int() c = new int(data.size());
int ptr = c.length - 1;
while (ptr >= 0) {
callback.accept(c);
c(ptr)++; // increment
if (c(ptr) == data.get(ptr).size()) { // carry
do {
ptr--;
} while(ptr >= 0 && c(ptr) == data.get(ptr).size() - 1);
if (ptr < 0) {
break;
}
c(ptr)++;
// zero out
while (++ptr <= c.length - 1) {
c(ptr) = 0;
}
ptr = c.length - 1;
}
}
// cheating - sort after generation and print result
combos.sort((o1, o2) -> Double.compare(o2.product, o1.product));
StringBuilder sb = new StringBuilder();
double totalP = 0;
for (int i = 0; i < combos.size(); i++) {
sb.append(String.format("%04d: ", i)).append(combos.get(i)).append("n");
totalP += combos.get(i).product;
}
System.out.printf("Cartesian product in descending product (total p=%.3e):n%s", totalP, sb.toString());
}
public static List asList(double() a) {
return Arrays.stream(a).boxed().collect(Collectors.toList());
}
public static List> createData(double()... arrays) {
final List> vals = new ArrayList<>();
Arrays.stream(arrays).forEachOrdered(a -> vals.add(asList(a)));
return vals;
}
static class Combo {
final double product;
final double() vals;
final int() indexes;
Combo(double product, double() vals, int() indexes) {
this.product = product;
this.vals = vals;
this.indexes = indexes;
}
@Override
public String toString() {
return new StringJoiner(", ", Combo.class.getSimpleName() + "(", ")")
.add("product=" + String.format("%.2e", product))
.add("vals=(" + Arrays.stream(vals).boxed().map(v -> String.format("%.2f", v)).collect(
Collectors.joining(", ")) + ")")
.add("indexes=" + Arrays.toString(indexes))
.toString();
}
}
}
```