with tutorial the framework español applications java java-8 java-stream chunking

java - tutorial - ¿Hay una forma elegante de procesar una secuencia en fragmentos?



the django project (2)

El uso de la biblioteca de la solución StreamEx se vería como

Stream<Integer> stream = IntStream.iterate(0, i -> i + 1).boxed().limit(15); AtomicInteger counter = new AtomicInteger(0); int chunkSize = 4; StreamEx.of(stream) .groupRuns((prev, next) -> counter.incrementAndGet() % chunkSize != 0) .forEach(chunk -> System.out.println(chunk));

Salida:

[0, 1, 2, 3] [4, 5, 6, 7] [8, 9, 10, 11] [12, 13, 14]

groupRuns acepta el predicado que decide si 2 elementos deben estar en el mismo grupo.

Produce un grupo tan pronto como encuentra el primer elemento que no le pertenece.

Mi escenario exacto es insertar datos en la base de datos en lotes, por lo que quiero acumular objetos DOM luego cada 1000, limpiarlos.

Lo implementé poniendo código en el acumulador para detectar plenitud y luego enjuagar, pero eso parece estar mal: el control de descarga debe provenir de la persona que llama.

Podría convertir la secuencia en una lista y luego usar sublista de manera iterativa, pero eso también parece torpe.

¿Hay una manera ordenada de tomar medidas cada n elementos y luego continuar con la secuencia mientras solo se procesa la secuencia una vez?


La elegancia está en el ojo del espectador. Si no te importa usar una función con estado en groupingBy , puedes hacer esto:

AtomicInteger counter = new AtomicInteger(); stream.collect(groupingBy(x->counter.getAndIncrement()/chunkSize)) .values() .forEach(database::flushChunk);

Esto no gana ningún punto de rendimiento o de uso de memoria con respecto a la solución original, ya que de todos modos materializará toda la secuencia antes de hacer cualquier cosa.

Si quiere evitar materializar la lista, la API de transmisión no lo ayudará. Deberá obtener el iterador o el spliterator de la secuencia y hacer algo como esto:

Spliterator<Integer> split = stream.spliterator(); int chunkSize = 1000; while(true) { List<Integer> chunk = new ArrayList<>(size); for (int i = 0; i < chunkSize && split.tryAdvance(chunk::add); i++){}; if (chunk.isEmpty()) break; database.flushChunk(chunk); }