任意数量集合的笛卡尔积

2022-08-31 16:36:02

您知道一些整洁的Java库吗,它们允许您制作两个(或更多)集合的笛卡尔积?

例如:我有三套。一个对象为“人”类,第二个对象为“礼物”类,第三个对象为“礼品扩展”类对象。

我想生成一个包含所有可能的三元组的设置 Person-Gift-GiftExtension。

集合的数量可能会有所不同,因此我无法在嵌套的foreach循环中执行此操作。在某些情况下,我的应用程序需要制作一个人 - 礼物对的产品,有时它是三重人 - 礼物 - 礼物扩展,有时甚至可能有设置人 - 礼品 - 礼品扩展 - 礼品二次扩展 - 礼品三次扩展等。


答案 1

编辑:删除了两组以前的解决方案。有关详细信息,请参阅编辑历史记录。

以下是对任意数量的集合递归执行此操作的方法:

public static Set<Set<Object>> cartesianProduct(Set<?>... sets) {
    if (sets.length < 2)
        throw new IllegalArgumentException(
                "Can't have a product of fewer than two sets (got " +
                sets.length + ")");

    return _cartesianProduct(0, sets);
}

private static Set<Set<Object>> _cartesianProduct(int index, Set<?>... sets) {
    Set<Set<Object>> ret = new HashSet<Set<Object>>();
    if (index == sets.length) {
        ret.add(new HashSet<Object>());
    } else {
        for (Object obj : sets[index]) {
            for (Set<Object> set : _cartesianProduct(index+1, sets)) {
                set.add(obj);
                ret.add(set);
            }
        }
    }
    return ret;
}

请注意,不可能将任何泛型类型信息与返回的集合一起保留。如果您事先知道要取多少个集合的乘积,则可以定义一个泛型元组来保存那么多元素(例如),但是在Java中没有办法拥有任意数量的泛型参数。Triple<A, B, C>


答案 2

这是一个相当古老的问题,但为什么不使用番石榴的笛卡尔产品呢


推荐