Получить два минимальных объекта из набора, используя поток Java - PullRequest
0 голосов
/ 24 декабря 2018

У меня есть Set некоторых объектов.Мне нужно получить два объекта min из Set.

. Мой пример выглядит следующим образом:

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Example {
     public static void main( String[] args ) {
         SomeObject obj1 = new SomeObject(1);
         SomeObject obj2 = new SomeObject(2);
         SomeObject obj3 = new SomeObject(3);
         Set<SomeObject> set = Stream.of(obj1,obj2,obj3)
                                     .collect(Collectors.toSet());

         SomeObject minObject= set.stream()
                                  .min(Comparator.comparingInt(object->object.getValue()))
                                  .get();
         System.out.println(minObject);
     }
}


class SomeObject{
    private int value;
    SomeObject(int value){
            this.value=value;
    }

    public int getValue() {
        return value;
    }

    @Override
    public String toString() {
        return this.value+"";
    }
}

В моем примере я могу получить объект min из этого Setдля атрибута значения.

Итак, мне нужно получить два минимальных значения, используя потоковые операции Java.

Ответы должны быть быстрыми, потому что в моей реальной программе я вызываю этот метод много раз, и мойнаборы очень большие.

Ответы [ 3 ]

0 голосов
/ 24 декабря 2018

Вы можете передать свой Set<E> экземпляру NavigableSet<E>, затем вы можете опросить первые два (самых низких) элемента из него:

final NavigableSet<SomeObject> navigableSet = new TreeSet<>(Comparator.comparingInt(SomeObject::getValue));

navigableSet.addAll(set);

final SomeObject firstMin = navigableSet.pollFirst();

final SomeObject secondMin = navigableSet.pollFirst();
0 голосов
/ 24 июня 2019

Один из способов сделать это за один проход через поток - написать собственный сборщик:

class MinCollector implements Consumer<SomeObject> {
    private TreeSet<SomeObject> minObjects = 
        new TreeSet<>(Comparator.comparingInt(o -> o.getValue()));

    public TreeSet<SomeObject> getMinObjects() {
        return minObjects;
    }

    @Override
    public void accept(SomeObject object) {
        minObjects.add(object);
        if(minObjects.size() > 2 ) {
            minObjects.remove(minObjects.last());
        }
    }

    public void combine(MinCollector collector) {
        for( SomeObject object : collector.minObjects ) {
            accept( object );
        }
    }
}

// ...
TreeSet<SomeObject> minObjects = set
    .stream()
    .collect(MinCollector::new, MinCollector::accept, MinCollector::combine)
    .getMinObjects();
0 голосов
/ 24 декабря 2018

Вы можете получить второе минимальное значение следующим образом:

 set.stream()
    .filter(s -> s.getValue() != minObject.getValue())     
    .min(Comparator.comparingInt(object -> object.getValue()))
    .get();
  • Это снова распространяется на набор элементов, гарантируя, что мы игнорируем предыдущее минимальное значение с помощью filter.
  • Затем мы получаем минимальное значение через min

, или вы можете получить оба одновременно:

Stream<SomeObject> twoMinValues = set.stream()
                   .sorted(Comparator.comparingInt(object -> object.getValue()))
                   .limit(2);
  • Это потоки по наборуэлементов, сортируя всю последовательность от наименьшего к наибольшему, а затем выбирая первые два, что определенно менее эффективно, чем описанный выше подход из-за поведения «отсортированной» промежуточной операции.

Awnser должен быть быстрым, потому что в моей настоящей программе я вызываю этот метод много раз, и мои наборы очень большие.

Что касается необходимости «быстрой» программы, я бы порекомендовал вам сначала попробоватьрешить проблему под рукой, просто используя типичный императивный подход, поскольку в большинстве случаев они быстрее, чем при использовании потоков.

если не намного лучше, тогда «подумайте» об использовании параллельных потоков, если и только если вы знаете, что можете использовать параллелизм.

см. Должен ли я всегда использовать параллельный поток, когда это возможно?

...