java - 如何选择集合中最大的元素之一

标签 java java-8 java-stream

我有一个元组列表,我想找到具有最大 x 值的元组。在存在多个最大 x 值的情况下,我想随机选择一个。我不知道如何实现这个随机选择功能。以下是我到目前为止的代码:

public void testSelectRandomFromLargestVals() {
    List<Tuple<Integer, String>> list = new ArrayList<>();
    list.add(new Tuple<>(5, "five-1"));
    list.add(new Tuple<>(2, "two"));
    list.add(new Tuple<>(3, "three"));
    list.add(new Tuple<>(5, "five-2"));
    list.add(new Tuple<>(5, "five-3"));

    Optional<Tuple<Integer, String>> largestTuple = list.stream().max((t1, t2) -> Integer.compare(t1.x, t2.x));
    System.out.println("Largest tuple is: " + largestTuple.get().x + " value is: " + largestTuple.get().y);
}

public class Tuple<X, Y> {
    public final X x;
    public final Y y;
    public Tuple(X x, Y y) {
        this.x = x;
        this.y = y;
    }
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Tuple<?, ?> tuple = (Tuple<?, ?>) o;
        if (!x.equals(tuple.x)) return false;
        return y.equals(tuple.y);
    }
    @Override
    public int hashCode() {
        int result = x.hashCode();
        result = 31 * result + y.hashCode();
        return result;
    }
}

最佳答案

事实证明Misha's一次性随机选择器(干得好,+1)可以与我的一次性最大值收集器结合使用 other answer到一个单一的 Collection 家。这允许在一次通过中从最大元素集中选择一个随机元素。

这是合并后的收集器:

static <T> Collector<T, ?, Optional<T>> rndMax(Comparator<? super T> cmp) {
    class RndMax {
        T val;
        int cnt;

        void add(T t) {
            int c;
            if (cnt == 0 || (c = cmp.compare(t, val)) > 0) {
                cnt = 1;
                val = t;
            } else if (c == 0) {
                cnt++;
                if (ThreadLocalRandom.current().nextInt(cnt) == 0) {
                    val = t;
                }
            }
        }

        RndMax merge(RndMax other) {
            if (cnt == 0) {
                return other;
            }

            if (other.cnt == 0) {
                return this;
            }

            int c = cmp.compare(val, other.val);
            if (c < 0) {
                return other;
            } else if (c > 0) {
                return this;
            } else {
                cnt += other.cnt;
                if (ThreadLocalRandom.current().nextInt(cnt) < other.cnt) {
                    val = other.val;
                }
                return this;
            }
        }

        Optional<T> finish() {
            return cnt == 0 ? Optional.empty() : Optional.of(val);
        }
    }

    return Collector.of(RndMax::new, RndMax::add, RndMax::merge, RndMax::finish);
}

你会像这样调用它:

List<Tuple<Integer,String>> list = ... ;
Optional<Tuple<Integer,String>> max =
    list.stream().collect(rndMax(Comparator.comparingInt(t -> t.x)));

关于java - 如何选择集合中最大的元素之一,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35997182/

相关文章:

java - 是否可以\建议重构 Spring MVC 应用程序以使用另一个 MVC 框架?

java - 需要帮助在 Adob​​e CQ 5.4 中创建带有监听器的组件

Java8 : Why a lambda expression could do a logical and(or) with boolean

java - 为什么对于大量数据,函数式比命令式快,而对于少量数据,函数式比命令式慢?

java - 如何使用 jersey 将 session 绑定(bind)到 User 对象

java - 从用于 Google map 标记的 SQLite 数据库中读取值

java - 等价于 Scala dropWhile

java - 在单个流中工作的多个线程

java - 如何在 groupingBy 操作中使用自定义收集器

java - 有条件地对流应用限制 - "stream has already been operated upon or closed"