Producto cartesiano de un número arbitrario de conjuntos.
¿Conoce algunas bibliotecas Java interesantes que le permitan crear un producto cartesiano de dos (o más) conjuntos?
Por ejemplo: tengo tres juegos. Uno con objetos de clase Persona, segundo con objetos de clase Regalo y tercero con objetos de clase GiftExtension.
Quiero generar un conjunto que contenga todos los triples posibles Persona-Regalo-Extensión de Regalo.
El número de conjuntos puede variar, por lo que no puedo hacer esto en un bucle foreach anidado. En algunas condiciones, mi aplicación necesita crear un producto del par Persona-Regalo, a veces es triple Persona-Regalo-Extensión de Regalo, a veces incluso puede haber conjuntos Persona-Regalo-Extensión de Regalo-RegaloSecondExtension-GiftThirdExtension, etc.
Editar: Se eliminaron las soluciones anteriores para dos conjuntos. Consulte el historial de edición para obtener más detalles.
Aquí hay una manera de hacerlo de forma recursiva para un número arbitrario de conjuntos:
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;
}
Tenga en cuenta que es imposible conservar información de tipo genérico con los conjuntos devueltos. Si supiera de antemano de cuántos conjuntos desea tomar el producto, podría definir una tupla genérica para contener esa cantidad de elementos (por ejemplo Triple<A, B, C>
), pero no hay forma de tener un número arbitrario de parámetros genéricos en Java.
Esta es una pregunta bastante antigua, pero ¿por qué no utilizar el producto cartesiano de Guava ?
El siguiente método crea el producto cartesiano de una lista de cadenas:
protected <T> List<List<T>> cartesianProduct(List<List<T>> lists) {
List<List<T>> resultLists = new ArrayList<List<T>>();
if (lists.size() == 0) {
resultLists.add(new ArrayList<T>());
return resultLists;
} else {
List<T> firstList = lists.get(0);
List<List<T>> remainingLists = cartesianProduct(lists.subList(1, lists.size()));
for (T condition : firstList) {
for (List<T> remainingList : remainingLists) {
ArrayList<T> resultList = new ArrayList<T>();
resultList.add(condition);
resultList.addAll(remainingList);
resultLists.add(resultList);
}
}
}
return resultLists;
}
Ejemplo:
System.out.println(cartesianProduct(Arrays.asList(Arrays.asList("Apple", "Banana"), Arrays.asList("Red", "Green", "Blue"))));
produciría esto:
[[Apple, Red], [Apple, Green], [Apple, Blue], [Banana, Red], [Banana, Green], [Banana, Blue]]