【数据结构与算法】多个list的笛卡尔积

一、何为笛卡尔积

笛卡尔乘积是指在数学中,两个集合X和Y的笛卡尔积(Cartesian product),又称直积,表示为X × Y,第一个对象是X的成员而第二个对象是Y的所有可能有序对的其中一个成员 。
例如:
假设集合A={a, b},集合B={0, 1, 2},
则两个集合的笛卡尔积为{(a, 0), (a, 1), (a, 2), (b, 0), (b, 1), (b, 2)}。

熟悉数据库的小伙伴们,肯定也知道,这个概念在数据库中,也经常使用。

二、Java实现

1、固定个数list的笛卡尔积的实现(自我实现)

这种实现方式弊端很大,就是list个数固定,不符合实际生产需要,但也是提供了一种思路(递归法)。
也就是,不管list的个数大小是多少,都会与最后一个list中的所有元素,做笛卡尔积。

测试如下:

 List<String> l1 = Arrays.asList("A", "B");
 List<String> l2 = Arrays.asList("A", "B", "C", "D");
 List<String> l3 = Arrays.asList("A", "B", "C");

 List<List<String>> lists = new ArrayList<>();

 List<String> item;
 for (String s : l1) {
     for (String s1 : l2) {
         for (String s2 : l3) {
             item = new ArrayList<>(List.of(s, s1, s2));
             lists.add(item);
         }
     }
 }

// 格式化输出,便于观察
for (int i = 0, len = l1.size() * l2.size() * l3.size(); i < len; i++) {
    System.out.print(lists.get(i) + "\t");
    if ((i + 1) % l3.size() == 0) {
        System.out.println();
    }
}

结果:
在这里插入图片描述

2、递归法(来自百度百科)

public static void main(String[] args) {

    List<String> l1 = Arrays.asList("A", "B");
    List<String> l2 = Arrays.asList("A", "B", "C", "D");
    List<String> l3 = Arrays.asList("A", "B", "C");

    List<List<String>> list = List.of(l1, l2, l3);

    List<List<String>> result = new ArrayList<>();

    descartes(list, result, 0, new ArrayList<>());

    // 格式化输出,便于观察
    for (int i = 0, len = l1.size() * l2.size() * l3.size(); i < len; i++) {
        System.out.print(result.get(i) + "\t");
        if ((i + 1) % l3.size() == 0) {
            System.out.println();
        }
    }
}

/**
 * description:笛卡尔乘积算法
 * <p>
 * 把一个List[ [1, 2], [3, 4], [a, b] ]
 * 转化成
 * List[ [1, 3, a], [1, 3, b], [1, 4, a], [1, 4, b], [2, 3, a], [2, 3, b], [2, 4, a], [2, 4, b] ]输出
 * </p>
 *
 * @param dimvalue 要计算笛卡尔积的List集合(dimensionality维度)
 * @param result   通过乘积转化后的数组
 * @param layer    中间参数,即原List的长度
 * @param curList  中间参数,保存每次计算的结果
 */
private static void descartes(List<List<String>> dimvalue,
                              List<List<String>> result,
                              int layer,
                              List<String> curList) {
    // 判断 计算到第几个list了
    if (layer < dimvalue.size() - 1) {
        // 该层list为null或无元素,则直接进入下一层
        List<String> layerList = dimvalue.get(layer);
        if (layerList == null || layerList.isEmpty()) {
            descartes(dimvalue, result, layer + 1, curList);
        } else {
            for (String item : layerList) {
                List<String> temp = new ArrayList<>(curList);
                temp.add(item);
                descartes(dimvalue, result, layer + 1, temp);
            }
        }
    } else if (layer == dimvalue.size() - 1) { // 到达最后一层list,也就是递归的终止条件
        // 该层list为null或无元素,则直接把curList放入结果集中
        List<String> endLayerList = dimvalue.get(layer);
        if (endLayerList == null || endLayerList.isEmpty()) {
            result.add(curList);
        } else {
            // 遍历最后一层list,与curList结合成新list,放入结果集result中
            for (String item : endLayerList) {
                List<String> temp = new ArrayList<>(curList);
                temp.add(item);
                result.add(temp);
            }
        }
    } else {
        // do nothing
    }
}

结果:
在这里插入图片描述

3、Guava工具类的实现(来自Google)

此种方式最为简单直接,list个数是动态的,感兴趣的小伙伴们,可自行阅读源码 Lists.cartesianProduct()

测试如下:

 List<String> l1 = Arrays.asList("A", "B");
 List<String> l2 = Arrays.asList("A", "B", "C", "D");
 List<String> l3 = Arrays.asList("A", "B", "C");

 List<List<String>> lists = Lists.cartesianProduct(l1, l2, l3);
 
 // 格式化输出,便于观察
 for (int i = 0, len = l1.size() * l2.size() * l3.size(); i < len; i++) {
     System.out.print(lists.get(i) + "\t");
     if ((i + 1) % l3.size() == 0) {
         System.out.println();
     }
 }

结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值