Dưới đây là một Iterable , cho phép bạn sử dụng đơn giản cho vòng lặp:
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 (")");
}
}
Làm cách nào? Chúng ta cần một Iterable, để sử dụng đơn giản cho vòng lặp, và một Iterator phải được trả về từ Iterable. Chúng tôi trả về một Danh sách các đối tượng - đây có thể là một Tập thay vì Danh sách, nhưng Bộ không có quyền truy cập được lập chỉ mục, do đó sẽ phức tạp hơn một chút, để triển khai thực hiện bằng Đặt thay vì Danh sách. Thay vì một giải pháp chung chung, Object sẽ tốt cho nhiều mục đích, nhưng generics cho phép hạn chế hơn.
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;
}
}
}
}
Công việc toán học được thực hiện trong phương pháp 'get'. Hãy suy nghĩ về 2 bộ của 10 yếu tố. Bạn có tổng cộng 100 kết hợp, được liệt kê từ 00, 01, 02, ... 10, ... đến 99. Đối với 5 X 10 phần tử 50, cho 2 X 3 phần tử 6 kết hợp. Modulo của kích thước danh sách con giúp chọn một phần tử cho mỗi lần lặp.
Iterable i điều thú vị nhất ở đây:
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);
}
}
Để thực hiện Iterable, cho phép người for-each loại vòng lặp, chúng ta phải thực hiện iterator(), và cho Iterator chúng ta phải thực hiện hasNext (), next() và remove().
Kết quả:
(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,)
Bạn có thể giải thích chính xác những gì bạn đang cố gắng hoàn thành không? – Rik
Câu hỏi này rất thú vị từ một nhà lý thuyết, quan điểm học thuật. Tôi rất ngạc nhiên khi tìm ra giải pháp sạch cho một câu hỏi dễ như thế này - nếu tôi đã tìm được một câu hỏi, tôi sẽ trả lời. Nhưng có điều này nói ... –
... Câu hỏi của bạn dường như nhắm mục tiêu một ứng dụng cụ thể, và có vẻ như tôi sẽ mất tất cả các loại nếu bạn chỉ đục mọi thứ vào bộ và những bộ đó thành một sản phẩm Descartes. Có lẽ cách tiếp cận của bạn là thiếu sót nghiêm trọng bằng cách suy nghĩ đến toán học và một vài về mặt OOP? –