Hier ist ein Iterable:
System.out.println(cartesianProduct(Arrays.asList(Arrays.asList("Apple", "Banana"), Arrays.asList("Red", "Green", "Blue"))));
dies ergäbe , mit dem Sie eine vereinfachte For-Schleife verwenden können:
import java.util.*;
// let's begin with the demo. Instead of Person and Gift,
// I use the well known char and int.
class CartesianIteratorTest {
public static void main (String[] args) {
List <Object> lc = Arrays.asList (new Object [] {'A', 'B', 'C', 'D'});
List <Object> lC = Arrays.asList (new Object [] {'a', 'b', 'c'});
List <Object> li = Arrays.asList (new Object [] {1, 2, 3, 4});
// sometimes, a generic solution like List <List <String>>
// might be possible to use - typically, a mixture of types is
// the common nominator
List <List <Object>> llo = new ArrayList <List <Object>>();
llo.add (lc);
llo.add (lC);
llo.add (li);
// Preparing the List of Lists is some work, but then ...
CartesianIterable <Object> ci = new CartesianIterable <Object> (llo);
for (List <Object> lo: ci)
show (lo);
}
public static void show (List <Object> lo) {
System.out.print ("(");
for (Object o: lo)
System.out.print (o + ", ");
System.out.println (")");
}
}
Wie wird es gemacht? Wir brauchen ein Iterable, um die vereinfachte For-Schleife zu verwenden, und ein Iterator muss vom Iterable zurückgegeben werden. Wir geben eine Liste von Objekten zurück - dies könnte ein Set anstelle von List sein, aber Set hat keinen indizierten Zugriff, daher wäre es etwas komplizierter, es mit Set statt List zu implementieren. Anstelle einer generischen Lösung wäre Objekt für viele Zwecke in Ordnung gewesen, aber Generika erlauben mehr Einschränkungen.
class CartesianIterator <T> implements Iterator <List <T>> {
private final List <List <T>> lilio;
private int current = 0;
private final long last;
public CartesianIterator (final List <List <T>> llo) {
lilio = llo;
long product = 1L;
for (List <T> lio: lilio)
product *= lio.size();
last = product;
}
public boolean hasNext() {
return current != last;
}
public List <T> next() {
++current;
return get (current - 1, lilio);
}
public void remove() {
++current;
}
private List<T> get (final int n, final List <List <T>> lili) {
switch (lili.size())
{
case 0: return new ArrayList <T>(); // no break past return;
default: {
List <T> inner = lili.get (0);
List <T> lo = new ArrayList <T>();
lo.add (inner.get (n % inner.size()));
lo.addAll (get (n/inner.size(), lili.subList (1, lili.size())));
return lo;
}
}
}
}
Die mathematische Arbeit erfolgt in der 'get'-Methode. Denken Sie über 2 Sätze von 10 Elementen nach. Sie haben insgesamt 100 Kombinationen, die von 00, 01, 02, ... 10, ... bis 99 gezählt werden. Für 5 X 10 Elemente 50, für 2 X 3 Elemente 6 Kombinationen. Der Modulo der Größe der Unterliste hilft, ein Element für jede Iteration auszuwählen.
Iterable i die am wenigsten interessante Sache hier:
class CartesianIterable <T> implements Iterable <List <T>> {
private List <List <T>> lilio;
public CartesianIterable (List <List <T>> llo) {
lilio = llo;
}
public Iterator <List <T>> iterator() {
return new CartesianIterator <T> (lilio);
}
}
Zur Umsetzung Iterable, die die für-jede Art von Schleife erlaubt, müssen wir iterator() implementieren, und für Iterator haben wir hasNext zu implementieren (), next() und remove().
Ergebnis:
(A, a, 1,)
(B, a, 1,)
(C, a, 1,)
(D, a, 1,)
(A, b, 1,)
(B, b, 1,)
(C, b, 1,)
(D, b, 1,)
...
(A, a, 2,)
...
(C, c, 4,)
(D, c, 4,)
Können Sie näher erläutern, was genau Sie erreichen möchten? – Rik
Diese Frage ist aus theoretischer Sicht sehr interessant. Ich war überrascht, wie schwierig es ist, eine saubere Lösung für eine einfache Frage wie diese zu finden - wenn ich eine gefunden hätte, hätte ich geantwortet. Aber wenn das gesagt wird ... –
... scheint Ihre Frage auf eine bestimmte Anwendung zu zielen, und es scheint mir so, als würden Sie alle Arten verlieren, wenn Sie einfach alles in Sätze und diese Sätze in ein kartesisches Produkt stanzen. Vielleicht ist Ihre Herangehensweise ernsthaft fehlerhaft, wenn Sie an mathematische und wenige an OOP denken? –