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

113
Views
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 answers
Answer question

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 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!