Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

116
Views
agrupar objetos usando Stream Collector

Tengo una lista de objetos, digamos de clase Documento:

 class Document { private final String id; private final int length; public Document(String id, int length) { this.id = id; this.length = length; } public int getLength() { return length; } }

La tarea en cuestión es agruparlos en Sobres para que el número de páginas (Documento.longitud) no exceda cierto número.

 class Envelope { private final List<Document> documents = new ArrayList<>(); }

Entonces, por ejemplo, si tuviera la siguiente lista de documentos:

 Document doc0 = new Document("doc0", 2); Document doc1 = new Document("doc1", 5); Document doc2 = new Document("doc2", 5); Document doc3 = new Document("doc3", 5);

y el recuento máximo de páginas en el sobre es digamos 7 , de lo que espero 3 sobres con los siguientes documentos:

 Assert.assertEquals(3, envelopeList.size()); Assert.assertEquals(2, envelopeList.get(0).getDocuments().size()); // doc0, doc1 Assert.assertEquals(1, envelopeList.get(1).getDocuments().size()); // doc2 Assert.assertEquals(1, envelopeList.get(2).getDocuments().size()); // doc3

He implementado esto con el bucle for tradicional y un montón de if, pero la pregunta es: ¿es posible hacerlo de esta manera más elegante con flujos y recopiladores?

Gracias y un saludo

dalibor

over 4 years ago · Santiago Trujillo
1 answers
Answer question

0

Para agrupar los documentos en lotes según la longitud, necesitamos mantener el estado de las longitudes acumuladas. Streams no son la mejor opción cuando es necesario mantener el estado externo y el bucle personalizado debe ser una opción más simple y eficiente.


Si forzamos el ajuste, las secuencias para este escenario, el DocumentSpliterator cambiaría de la siguiente manera:

 public static List<Couvert> splitDocuments(List<Document> docs) { IntUnaryOperator helper = new IntUnaryOperator() { private int bucketIndex = 0; private int accumulated = 0; public synchronized int applyAsInt(int length) { if (length + accumulated > MAX) { bucketIndex++; accumulated = 0; } accumulated += length; return bucketIndex; } }; return new ArrayList<>(docs.stream() .map(d -> new AbstractMap.SimpleEntry<>(helper.applyAsInt(d.getLength()), d)) .collect(Collectors.groupingBy(AbstractMap.SimpleEntry::getKey, Collector.of(Couvert::new, (c, e) -> c.getDocuments().add(e.getValue()), (c1, c2) -> {c1.getDocuments().addAll(c2.getDocuments());return c1;}))) .values()); }

Explicación:

  • helper mantiene la longitud acumulada y proporciona un nuevo índice de cubo cuando supera el máximo. He usado la interfaz IntUnaryOperator aquí. Alternativamente, podemos usar cualquier interfaz que tome un parámetro int y devuelva un int .
  • En cuanto a la corriente,
    • Document se asigna a una entrada simple de SimpleEntry y Document.
    • El flujo de SimpleEntry se agrupa primero según el bucketIndex. Otro Collector transforma el flujo de Document para un bucketIndex en particular en un Couvert . La salida de collect() es Map<Integer,Couvert>
  • Finalmente, la Collection de Couvert se convierte en una lista y se devuelve.

Nota: Para esta implementación, eliminé el parámetro front y lo incluí como parte de la lista de docs .

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!