¿Hay una manera de comprobar si una corriente contiene todos los elementos de la colección?

Nolequen:

Por ejemplo, necesito algo como:

Collection<String> collection = /* ... */;
Stream<Object> stream = /* ... */;
boolean containsAll = stream.map(Object::toString).containsAll(collection);

Por supuesto, podría acumular todos los elementos de la corriente a otra Collectionutilizando collect()el método y la llamada Collection.containsAll(), pero lo que si la corriente es demasiado grande y es ineficiente para procesar todos sus elementos?

ETO:

Esto debería funcionar:

Set<String> set = new HashSet<>(collection);
boolean containsAll = set.isEmpty() || stream.map(Object::toString)
                                             .anyMatch(s -> set.remove(s) && set.isEmpty());

La solución podría parecer confuso, pero la idea es sencilla:

  1. Con el fin de evitar múltiples iteraciones sobre collectionla envolvemos en una HashSet. (En caso de que su streames uno paralelo, entonces usted tendrá que utilizar un conjunto de hash concurrente. Ver este post para más detalles)
  2. Si el collection(o set) está vacía, entonces volvemos truesin procesar elstream
  3. Para cada entrada del streamtratamos de sacarlo de set. En caso de que el resultado de Set::removees true(por lo tanto, fue contenido por set) y el setestá vacía después de la extracción, se puede concluir que streamcontenía todos los elementos de la inicial collection.
  4. El funcionamiento del terminal Stream::anyMatches un cortocircuito en uno. Por lo tanto, se detendrá la iteración más de streamuna vez que el setusuario está vacía. En peor de los casos vamos a procesar toda la corriente.

Quizás esta es una forma poco más legible:

Set<String> set = new HashSet<>(collection);
boolean containsAll = set.isEmpty() || stream.map(Object::toString)
                                             .filter(set::remove)
                                             .anyMatch(__ -> set.isEmpty());

Si el collectionpuede contener duplicados y no es un requisito para comprobar si streamcontiene todos ellos, entonces necesitaremos para mantener un mapa concurrente de contadores.

Map<String, AtomicLong> map = new ConcurrentHashMap<>();
collection.forEach(s -> map.computeIfAbsent(s, __ -> new AtomicLong()).incrementAndGet());
boolean containsAll = map.isEmpty() || stream.map(Object::toString)
                                             .filter(map::containsKey)
                                             .filter(s -> map.get(s).decrementAndGet() == 0)
                                             .filter(s -> map.remove(s) != null)
                                             .anyMatch(__ -> map.isEmpty());

El código modificado ligeramente, pero la idea es la misma.

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=311887&siteId=1
Recomendado
Clasificación