使用Java流从集合中获取两个min对象

时间:2018-12-24 19:23:18

标签: java lambda java-8 set java-stream

我有一些物品。我需要从Set中获取两个min对象。

我的示例如下:

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

在我的示例中,我可以基于value属性从此Set中获取min对象。

因此,我需要使用java流操作来获取两个min值。

遮阳篷应该很快,因为在我的真实程序中,我多次调用此方法,并且集合很大。

3 个答案:

答案 0 :(得分:5)

您可以获取第二个最小值,如下所示:

 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);
  • 这会流过元素集,将整个序列从最小到最大排序,然后采用前两个,由于“已排序”的中间操作的行为,其效率肯定比上述方法低。
  

遮阳篷应该很快,因为在我的真实程序中,我称之为   方法很多次,我的集合很大。

关于需要“快速”程序,我建议您首先尝试使用典型的命令式方法来解决当前的问题,因为在大多数情况下,它们比使用流更快。

如果并没有更好,那么仅当您知道可以利用并行性时,才“考虑”使用并行流。

请参阅Should I always use a parallel stream when possible?

答案 1 :(得分:2)

您可以将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();

答案 2 :(得分:0)

通过流一次完成此操作的一种方法是编写一个自定义收集器:

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