Java でデカルト積(直積)

Python でデカルト積(直積) - Oboe吹きプログラマの黙示録
に触発されて、Java 環境でのデカルト積を求めるものを作りました。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
/**
 * デカルト積(直積)生成.
 * 同じ型の Listを複数渡して、デカルト積を求める。
 */
public class Cartesian<T> {
    private List<T>[] lists;

    /**
     * 複数List →インスタンス生成.
     * @param lists 要素のリスト
     * @return インスタンス
     */
    @SuppressWarnings("unchecked")
    public static <T> Cartesian<T> of(List<T>...lists){
        if (lists.length < 1) throw new IllegalArgumentException("require argument List");
        return new Cartesian<T>(lists);
    }

    @SuppressWarnings("unchecked")
    private Cartesian(List<T>...lists){
        this.lists = lists;
    }

    /**
     * デカルト積生成
     * @return Listの入れ子
     */
    public List<List<T>> product(){
        int total = 1;
        int[] max = new int[lists.length];
        for(int i=0; i < lists.length; i++){
            max[i] = lists[i].size();
        }
        int[] initProduct = new int[lists.length];
        Arrays.fill(initProduct, 1);
        for(List<T> list:lists){
            total *= list.size();
        }
        List<List<T>> rlist = new ArrayList<>();
        int finalTotal = total;
        Iterator<List<T>> itr = new Iterator<List<T>>() {
            int index = -1;
            int[] presentProduct;
            @Override
            public boolean hasNext(){
                index++;
                return index < finalTotal;
            }
            @Override
            public List<T> next() {
                if (index == 0){
                    presentProduct = initProduct;
                }else{
                    presentProduct = generateNextProduct(presentProduct, max);
                }
                List<T> result = new ArrayList<>();
                for(int i=0; i < presentProduct.length; i++){
                    result.add(lists[i].get(presentProduct[i] - 1));
                }
                return result;
            }
        };
        itr.forEachRemaining(rlist::add);
        return rlist;
    }

    /**
     * デカルト積リストのIterable生成
     * @return List の Iterable
     */
    public Iterable<List<T>> iterable(){
        int total = 1;
        int[] max = new int[lists.length];
        for(int i=0; i < lists.length; i++){
            max[i] = lists[i].size();
        }
        int[] initProduct = new int[lists.length];
        Arrays.fill(initProduct, 1);
        for(List<T> list:lists){
            total *= list.size();
        }
        int finalTotal = total;
        return () -> new Iterator<List<T>>() {
            int index = -1;
            int[] presentProduct;
            @Override
            public boolean hasNext(){
                index++;
                return index < finalTotal;
            }
            @Override
            public List<T> next() {
                if (index == 0){
                    presentProduct = initProduct;
                }else{
                    presentProduct = generateNextProduct(presentProduct, max);
                }
                List<T> result = new ArrayList<>();
                for(int i=0; i < presentProduct.length; i++){
                    result.add(lists[i].get(presentProduct[i] - 1));
                }
                return result;
            }
        };
    }

    private int[] generateNextProduct(int[] curr, int[] max){
        int n = curr.length - 1;
        curr[n]++;
        for(int i=n; i > 0; i--){
            if (curr[i] > max[i]){
                curr[i] = 1;
                curr[i-1]++;
            }
        }
        return curr;
    }
}

使用例

List<String> list1 = Arrays.asList("A", "B", "C");
List<String> list2 = Arrays.asList("1", "2");

Cartesian<String> cartesian = Cartesian.of(list1, list2);
List<List<String>> rlist = cartesian.product();

System.out.println(rlist);

標準出力結果

[[A, 1], [A, 2], [B, 1], [B, 2], [C, 1], [C, 2]]

yipuran-core に追加しました。
https://github.com/yipuran/yipuran-core/wiki/pch#%E3%83%87%E3%82%AB%E3%83%AB%E3%83%88%E7%A9%8Dorgyipuranutilpchcartesian