【问题标题】:Cartesian product of large number of sets大集合的笛卡尔积
【发布时间】:2020-07-05 09:11:54
【问题描述】:

我有List<List<T>> input,我需要从中生成笛卡尔积。我试图使用Lists.cartesianProduct(input),但问题是笛卡尔积的大小大于Integer.MAX_VALUE,并且方法抛出异常。我在网上找到的所有算法都有类似的问题(如果你想保留完整的列表功能,它们会受到List 最大大小的限制,即Integer.MAX_VALUE)。我想到的唯一解决方案是创建自己的列表实现,使用long 而不是int 进行索引,但我无法使用List 接口,这将非常麻烦,所以这确实是最后的手段。还有其他方法吗?只要我拥有所有可能的组合,输出就不必是列表。

【问题讨论】:

  • 您确定要在内存中生成这些吗?
  • 看起来像发电机将是要走的路。
  • @Kayaman 我更喜欢它在内存中,因为我仍然需要进一步处理它,但是将其保存到文件的解决方案是可以接受的解决方法,所以如果你能提出一些解决方案,我将不胜感激。
  • @ggorlen 原生生成器,例如 Stream.generate(Supplier<T>)?
  • @ggorlen 好吧,那里的第二个答案确实用流回答了给定的问题,因为这是关于基于数组的延迟流式传输而不是本身生成,所以我认为它很好。

标签: java algorithm


【解决方案1】:

构建一个迭代笛卡尔积并调用用户提供的函数而不是构建它们的列表的解决方案非常容易。这样,完整的产品永远不会在内存中。如果您希望将结果存储在文件中,您也可以这样做,只需提供一个写入文件的函数即可。

<T> void cartesianProduct(List<List<T>> items, Consumer<List<T>> consumer) {
    recurse(items, consumer, new ArrayList<>());
}

<T> void recurse(List<List<T>> items, Consumer<List<T>> consumer, List<T> prefix) {
    if (items.isEmpty()) {
        consumer.accept(prefix);
    } else {
        List<T> first = items.get(0);
        List<List<T>> rest = items.subList(1, items.size());
        for (T item : first) {
            prefix.add(item);
            recurse(rest, consumer, prefix);
            prefix.remove(prefix.size() - 1);
        }
    }
}

例如,这会将笛卡尔积打印到 System.out:

cartesianProduct(List.of(
    List.of("1", "2"), List.of("A", "B"), List.of("!", "@")
), System.out::println);

【讨论】:

    猜你喜欢
    • 2012-09-07
    • 2015-01-28
    • 2010-10-17
    • 2018-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多