任意数量集合的笛卡尔积
您是否知道一些简洁的 Java 库可以让您生成两个(或更多)集合的笛卡尔积?
例如:我有三套。 第一个是 Person 类的对象,第二个是 Gift 类的对象,第三个是 GiftExtension 类的对象。
我想生成一组包含所有可能的三元组 Person-Gift-GiftExtension。
集合的数量可能会有所不同,因此我无法在嵌套的 foreach 循环中执行此操作。 在某些情况下,我的应用程序需要制作 Person-Gift 对的乘积,有时是三重 Person-Gift-GiftExtension,有时甚至可能有集合 Person-Gift-GiftExtension-GiftSecondExtension-GiftThirdExtension 等。
Do you know some neat Java libaries that allow you to make cartesian product of two (or more) sets?
For example: I have three sets. One with objects of class Person, second with objects of class Gift and third with objects of class GiftExtension.
I want to generate one set containing all possible triples Person-Gift-GiftExtension.
The number of sets might vary so I cannot do this in nested foreach loop.
Under some conditions my application needs to make a product of Person-Gift pair, sometimes it is triple Person-Gift-GiftExtension, sometimes there might even be sets Person-Gift-GiftExtension-GiftSecondExtension-GiftThirdExtension, etc.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(11)
基于索引的解决方案
使用索引是一种快速、内存高效且可以处理任意数量的集合的替代方案。 实现 Iterable 可以在 for-each 循环中轻松使用。 有关使用示例,请参阅#main 方法。
Index-based solution
Working with the indices is an alternative that is fast and memory-efficient and can handle any number of sets. Implementing Iterable allows easy use in a for-each loop. See the #main method for a usage example.
两个提示:
Two hints:
这是一个 Iterable,它允许您使用简化的 for 循环:
它是如何完成的? 我们需要一个 Iterable,以使用简化的 for 循环,并且必须从 Iterable 返回一个 Iterator。
我们返回一个对象列表 - 这可能是一个 Set 而不是 List,但是 Set 没有索引访问,因此使用 Set 而不是 List 来实现它会更复杂一些。 如果不是通用解决方案,对象可以满足多种用途,但泛型允许更多限制。
数学工作是通过“get”方法完成的。 考虑 2 组 10 个元素。 您总共有 100 种组合,从 00、01、02、... 10、... 到 99。对于 5 X 10 元素,有 50 种组合;对于 2 X 3 元素,有 6 种组合。 子列表大小的模有助于为每次迭代选择一个元素。
Iterable是这里最不有趣的事情:
为了实现Iterable,它允许for-each类型的循环,我们必须实现iterator(),对于Iterator我们必须实现hasNext()、next()和remove()。
结果:
Here is an Iterable, which allows you to use a simplified for-loop:
How is it done? We need an Iterable, to use the simplified for-loop, and an Iterator has to be returned from the Iterable.
We return a List of Objects - this could be a Set instead of List, but Set has no indexed access, so it would be a bit more complicated, to implement it with Set instead of List. Instead of a generic solution, Object would have been fine for many purposes, but generics allow for more restrictions.
The mathematical work is done in the 'get'-method. Think about 2 sets of 10 elements. You have a total of 100 combinations, enumerated from 00, 01, 02, ... 10, ... to 99. For 5 X 10 elements 50, for 2 X 3 elements 6 combinations. The modulo of the sublist size helps to pick one element for each iteration.
Iterable i the least interesting thing here:
To implement Iterable, which allows the for-each kind of loop, we have to implement iterator (), and for Iterator we have to implement hasNext (), next () and remove ().
Result:
这是一个迭代器,它给出二维数组的笛卡尔积,其中数组组件代表问题中的集合(人们总是可以将实际的集合转换为数组):
基本思想是将
count
视为多基数(数字i
有自己的基数,等于i
的长度第一个“集合”)。 每当我们必须解析next
时(即,当调用hasNext()
且next
为null
时),我们将这个数字分解成这个多基数中的数字。 这些数字现在用作我们从不同集合中提取元素的索引。使用示例:
输出:
如果不喜欢数组,则代码可以轻松转换为使用集合。
我想这或多或少类似于“用户未知”给出的答案,只是没有递归和集合。
Here is an
Iterator
that gives the cartesian product of a two-dimensional array, where the arrays components represent the sets from the question (one can always convert actualSet
s to arrays):The basic idea is to treat
count
as a multi-radix number (digiti
has its own radix which equals the length of thei
'th "set"). Whenever we have to resolvenext
(that is, whenhasNext()
is called andnext
isnull
), we decompose the number into its digits in this multi-radix. These digits are now used as the indices from which we draw elements from the different sets.Example use:
Output:
If one doesn't like arrays, the code is trivially convertible into using collections.
I guess this is more or less similar to the answer given by "user unknown", only without recursion and collections.
您可以获取任意数量的不同类型集合的笛卡尔积并将其存储到对象
Set<的集合集合中;使用 Java 9 Streams 设置
在线试用!
输出:
另请参阅:如何创建数据类似于三个不同类型列表的笛卡尔积的结构?
You can get the Cartesian product of an arbitrary number of sets of different types and store it into a set of sets of objects
Set<Set<Object>>
using Java 9 Streams as follows:Try it online!
Output:
See also: How to create a data structure similar to the cartesian product of three lists of different types?
是的,有函数式 Java。
对于集合
s
:Yes, there is Functional Java.
For a set
s
:例如,对于整数集,一个简单的解决方案应如下所示:
a simple solution, for example, for Integer set should be as follows:
您可以通过此库应用一个名为
Seq
的简单生成器接口。 与 不同Guava 的 cartesianProduct,集合/列表/迭代不需要位于相同的泛型类型绑定B
内,所有类型都受欢迎。 您所需要做的就是将乘积编写为普通的嵌套 for 循环。结果将是
You can apply a simple generator interferace named
Seq
via this library. Unlike Guava's cartesianProduct, the sets/lists/iterables do not need to be within the same generic type boundB
, all types are welcome. And all you need to do is writing the product as normal nested for-loops.The result would be
编辑:删除了之前的两套解决方案。 有关详细信息,请参阅编辑历史记录。
这是一种对任意数量的集合递归执行此操作的方法:
请注意,不可能在返回的集合中保留任何通用类型信息。 如果您事先知道要获取多少个集合的乘积,则可以定义一个通用元组来保存那么多元素(例如
Triple
),但是有Java 中无法拥有任意数量的泛型参数。Edit: Previous solutions for two sets removed. See edit history for details.
Here is a way to do it recursively for an arbitrary number of sets:
Note that it is impossible to keep any generic type information with the returned sets. If you knew in advance how many sets you wanted to take the product of, you could define a generic tuple to hold that many elements (for instance
Triple<A, B, C>
), but there is no way to have an arbitrary number of generic parameters in Java.这是一个非常老的问题,但为什么不使用 Guava 的笛卡尔积?
This is a pretty old question, but why not use Guava's cartesianProduct?
下面的方法创建字符串列表列表的笛卡尔积:
示例:
将产生以下结果:
The method below creates the cartesian product of a list of list of strings:
Example:
would yield this: