5

I have a Collection<List<SomeObject>> values

How can I find the collection with the largest list using Streams?

I have tried something like this, but it doesn't quite work

values.stream().max(e -> e.stream().max(List::size).get()).get()

But I get compilation error. Any ideas?

Alexis C.
  • 91,686
  • 21
  • 171
  • 177
Shervin Asgari
  • 23,901
  • 30
  • 103
  • 143

2 Answers2

15

I think you want

 values.stream().max(Comparator.comparingInt(List::size)).get()

If you need duplicates, the best solution I can think of would be something like

values.stream()
   .collect(Collector.of(
      ArrayList::new,
      (List<List<SomeObject>> best, List<SomeObject> elem) -> {
        if (best.isEmpty()) {
          best.add(elem);
        } else if (best.get(0).size() < elem.size()) {
          best.clear();
          best.add(elem);
        }
      },
      (best1, best2) -> {
        if (best1.isEmpty() || best2.isEmpty()
              || best1.get(0).size() == best2.get(0).size()) {
          best1.addAll(best2);
          return best1;
        } else if (best1.get(0).size() > best2.get(0).size()) {
          return best1;
        } else {
          return base2;
        }
      }));
Louis Wasserman
  • 191,574
  • 25
  • 345
  • 413
  • Yeah, I just figured it out before you answered :) – Shervin Asgari Jan 13 '16 at 20:26
  • One problem I get is that my maximum has two entries. So I should have gotten both results, however it only chooses the first I guess. How can I get the max, but also duplicates? – Shervin Asgari Jan 13 '16 at 20:33
  • 2
    @ShervinAsgari See http://stackoverflow.com/questions/29334404/how-to-force-max-to-return-all-maximum-values-in-a-java-stream/29334774 – Alexis C. Jan 13 '16 at 20:38
  • I found out why: http://stackoverflow.com/questions/31790372/java-8-stream-max-with-duplicates. Seems I cant use sort if I want duplicates – Shervin Asgari Jan 13 '16 at 20:38
  • 2
    I suppose you could probably write a special-cased `Collector` for it, but that would be hard. – Louis Wasserman Jan 13 '16 at 20:39
  • 2
    @ShervinAsgari my answer now provides a `Stream`-based solution that works in a single pass, though it does take a fair amount of work. – Louis Wasserman Jan 13 '16 at 20:55
  • 2
    I doubt you tested it because it doesn't compile since the collect method you are using requires a BiConsumer as combiner. Also it seems you missed to add the list in your accumulator if its size is the same as the max size already stored. Anyway the implementation in the linked question is far more reusable. – Alexis C. Jan 13 '16 at 21:06
  • 2
    @AlexisC. I'm fine with that. No, I didn't test it. – Louis Wasserman Jan 13 '16 at 21:07
3

My StreamEx library provides a ready collector to find all the maximal elements:

List<List<SomeObject>> result = values.stream()
                .collect(MoreCollectors.maxAll(Comparator.comparingInt(List::size)));
Tagir Valeev
  • 97,161
  • 19
  • 222
  • 334