Saltar al contenido

¿Cómo puedo hacer un producto cartesiano con flujos de Java 8?

No dudes en compartir nuestro sitio y códigos en tus redes sociales, apóyanos para ampliar nuestra comunidad.

Solución:

Puedes resolver esto usando el recursivo flatMap cadena.

Primero, como necesitamos movernos hacia adelante y hacia atrás por los valores del mapa, es mejor copiarlos en el ArrayList (esta no es la copia profunda, en tu caso es ArrayList de solo 3 elementos, por lo que el uso de memoria adicional es bajo).

En segundo lugar, para mantener un prefix de los elementos visitados anteriormente, creemos un ayudante inmutable Prefix clase:

private static class Prefix 
    final T value;
    final Prefix parent;

    Prefix(Prefix parent, T value) 
        this.parent = parent;
        this.value = value;
    

    // put the whole prefix into given collection
    > C addTo(C collection) 
        if (parent != null)
            parent.addTo(collection);
        collection.add(value);
        return collection;
    

Esta es una lista enlazada inmutable muy simple que se puede usar así:

List list = new Prefix<>(new Prefix<>(new Prefix<>(null, "a"), "b"), "c")
                          .addTo(new ArrayList<>()); // [a, b, c];

A continuación, creemos el método interno que encadena flatMaps:

private static > Stream comb(
        List> values, int offset, Prefix prefix,
        Supplier supplier) 
    if (offset == values.size() - 1)
        return values.get(offset).stream()
                     .map(e -> new Prefix<>(prefix, e).addTo(supplier.get()));
    return values.get(offset).stream()
            .flatMap(e -> comb(values, offset + 1, new Prefix<>(prefix, e), supplier));

Parece recursividad, pero es más complejo: no se llama a sí mismo directamente, sino que pasa lambda que llama al método externo. Parámetros:

  • valores: el List de valores originales (new ArrayList<>(map.values) en tu caso).
  • desplazamiento: el desplazamiento actual dentro de esta lista
  • prefix: la corriente prefix de desplazamiento de longitud (o null Si offset == 0). Contiene elementos seleccionados actualmente de las colecciones. list.get(0), list.get(1) hasta list.get(offset-1).
  • proveedor: el método de fábrica para crear la colección resultante.

Cuando llegamos al final de la lista de valores (offset == values.size() - 1), mapeamos los elementos de la última colección desde los valores hasta la combinación final utilizando el proveedor. De lo contrario usamos el flatMap que para cada elemento intermedio agranda el prefix y llama al comb método de nuevo para el próximo desplazamiento.

Finalmente, aquí está el método público para usar esta función:

public static > Stream ofCombinations(
        Collection> values, Supplier supplier) 
    if (values.isEmpty())
        return Stream.empty();
    return comb(new ArrayList<>(values), 0, null, supplier);

Un ejemplo de uso:

Map> map = new LinkedHashMap<>(); // to preserve the order
map.put("A", Arrays.asList("a1", "a2", "a3", "a4"));
map.put("B", Arrays.asList("b1", "b2", "b3"));
map.put("C", Arrays.asList("c1", "c2"));

ofCombinations(map.values(), LinkedHashSet::new).forEach(System.out::println);

Recopilamos combinaciones individuales para LinkedHashSet de nuevo para preservar el orden. En su lugar, puede utilizar cualquier otra colección (p. Ej. ArrayList::new).

Una solución que opera principalmente sobre listas, simplificando mucho las cosas. Hace una llamada recursiva flatMap, realiza un seguimiento de los elementos que ya se han combinado y las colecciones de elementos que aún faltan, y ofrece los resultados de esta construcción recursiva anidada como un flujo de listas:

import java.util.*;
import java.util.stream.Stream;

public class CartesianProduct 

    public static void main(String[] args) 
        Map> map = 
            new LinkedHashMap>();
        map.put("A", Arrays.asList("a1", "a2", "a3", "a4"));
        map.put("B", Arrays.asList("b1", "b2", "b3"));
        map.put("C", Arrays.asList("c1", "c2"));
        ofCombinations(map.values()).forEach(System.out::println);
    

    public static  Stream> ofCombinations(
        Collection> collections) 
        return ofCombinations(
            new ArrayList>(collections), 
            Collections.emptyList());        
           

    private static  Stream> ofCombinations(
        List> collections, List current) 
        return collections.isEmpty() ? Stream.of(current) :
            collections.get(0).stream().flatMap(e -> 
            
                List list = new ArrayList(current);
                list.add(e);
                return ofCombinations(
                    collections.subList(1, collections.size()), list);
            );
    

Producto cartesiano en Java 8 con forEach:

List listA = new ArrayList<>();
listA.add("0");
listA.add("1");
List listB = new ArrayList<>();
listB.add("a");
listB.add("b"); 

List cartesianProduct = new ArrayList<>();
listA.forEach(a -> listB.forEach(b -> cartesianProduct.add(a + b)));

cartesianProduct.forEach(System.out::println);
//Output : 0a 0b 1a 1b 

valoraciones y reseñas

Si haces scroll puedes encontrar las reseñas de otros usuarios, tú asimismo tienes la habilidad dejar el tuyo si te apetece.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *