Me gustaría comparar flujos y verificar si tienen 1 o más elementos en común (encontrar 1 es suficiente para dejar de buscar más). Quiero poder aplicar esto a Streams que contengan una clase creada a medida.
A modo de ilustración, digamos que tengo una clase que se parece a:
public class Point { public final int row; public final int col; public Point(int row, int col) { this.row = row; this.col = col; } @Override public boolean equals(Object obj) { if (obj == null) return false; if (obj.getClass() != this.getClass()) return false; final Point other = (Point) obj; return this.row == other.row && this.col == other.col; } @Override public int hashCode() { return Objects.hash(row, col); } }Y luego tengo dos hermosos flujos que se ven así:
Stream<Point> streamA = Stream.of(new Point(2, 5), new Point(3, 1)); Stream<Point> streamB = Stream.of(new Point(7, 3), new Point(3, 1)); Dado que estos flujos tienen 1 punto en común (a saber, Point(3, 1) ), me gustaría que el resultado final fuera verdadero.
La funcionalidad deseada se puede representar como:
public static boolean haveSomethingInCommon(Stream<Point> a, Stream<Point> b){ //Code that compares a and b and returns true if they have at least 1 element in common }Sin recopilar los dos flujos de forma independiente, puede agrupar e identificar si se asignan varios valores a cualquier clave.
public static boolean haveSomethingInCommon(Stream<Coord> a, Stream<Coord> b) { return Stream.concat(a, b) .collect(Collectors.groupingBy(Function.identity())) .values().stream() .anyMatch(l -> l.size() > 1); }Si la misma transmisión puede tener el mismo elemento dos veces o más , puede cambiar el código que se usará:
Stream.concat(a.distinct(), b.distinct())En primer lugar, debe convertir sus flujos en un conjunto o lista para no obtener el famoso error:
java.lang.IllegalStateException: stream has already been operated upon or closed Y luego puedes usar anyMatch así:
public static boolean haveSomethingInCommon(Stream<Coord> a, Stream<Coord> b) { Set<Coord> setA = a.collect(Collectors.toSet()); Set<Coord> setB = b.collect(Collectors.toSet()); return setA.stream().anyMatch(setB::contains); } O puede convertir solo el flujo b en un conjunto y usar:
public static boolean haveSomethingInCommon(Stream<Coord> a, Stream<Coord> b) { Set<Coord> setB = b.collect(Collectors.toSet()); return a.anyMatch(setB::contains); } Recomendaría Set<Coord> en lugar de Stream<Coord> como parámetro en su método.
public static boolean haveSomethingInCommon(Set<Coord> a, Set<Coord> b) { return a.stream().anyMatch(b::contains); }hay una función disjoint en Collections :
public static boolean haveSomethingInCommon( Stream<Coord> a, Stream<Coord> b ) { return( ! Collections.disjoint( a.collect( toList() ), b.collect( toList() ) ) ); }