Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

115
Visualizações
group objects using stream collector

I have list of objects, let's say of class Document:

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;
    }
}

Task at hand is to group them in Envelopes so that number of pages (Document.length) does not exceed certain number.

class Envelope {

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

So for example, if I had follwing List of Documents:

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

and max page count in envelope is let's say 7, than I expect 3 envelopes with following documents:

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

I have implemented this with traditional for loop and bunch of if's but question is, is it possible to do this more elegant way with streams and collectors?

thank you and best regards

Dalibor

over 4 years ago · Santiago Trujillo
1 Respostas
Responde à pergunta

0

For batching the documents based on the length, we need to maintain the state of accumulated lengths. Streams are not the best choice when external state needs to be maintained and custom loop should be simpler and efficient option.


If we force fit, streams for this scenario, the DocumentSpliterator would change as below:

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());
}

Explanation:

  • helper maintains the accumulated length and provides a new bucket index when it exceeds max. I have used IntUnaryOperator interface here. Alternatively, we can use any interface that takes an int parame and returns an int.
  • Regarding the stream,
    • Document is mapped to a SimpleEntry of bucketIndex and Document.
    • The stream of SimpleEntry is first grouped based on the bucketIndex. Another Collector transforms the stream of Document for a particuar bucketIndex to a Couvert. Output of the collect() is Map<Integer,Couvert>
  • Finally, the Collection of Couvert are converted to a list and returned.

Note: For this implementation, I removed the front parameter and included it as part of the docs list.

over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda