Java 8集合最大大小与计数

问题描述 投票:3回答:4

我有一个类似下面的课程。

class Student {
    public Student(Set<String> seminars) {
        this.seminar = seminars;
    }
    Set<String> seminar;
    public Set<String> getSeminar()
    {
        return seminar;
    }
}

并创建了一组像下面这样的学生。

List<Student> students = new ArrayList<Student>();
Set<String> seminars = new HashSet<String>();

seminars.add("SeminarA");
seminars.add("SeminarB");
seminars.add("SeminarC");

students.add(new Student(seminars)); //Student 1 - 3 seminars
students.add(new Student(seminars)); //Student 2 - 3 seminars

seminars = new HashSet<String>();
seminars.add("SeminarA");
seminars.add("SeminarB");

students.add(new Student(seminars)); //Student 3 - 2 seminars

seminars = new HashSet<String>();
students.add(new Student(seminars)); //Student 4 - 0 seminars

现在的问题是“我正在努力让那些参加过maximus研讨会的学生数量众多”正如你所看到的那样,有2名学生参加过3次(最多)研讨会,所以我需要了解这一点。

我使用流使用2个不同的语句实现了相同的功能

OptionalInt max = students.stream()
    .map(Student::getSeminar)
    .mapToInt(Set::size)
    .max();
long count = students.stream()
    .map(Student::getSeminar)
    .filter(size -> size.size() == max.getAsInt())
    .count();

有没有办法用一个声明来实现同样的目的?

java-8 java-stream
4个回答
2
投票

要解决此问题,请使用以下代码:

students.stream()
    .map(Student::getSeminar)
    .collect(Collectors.groupingBy(Set::size, Collectors.counting()));

你的输出将是:

{0=1, 2=1, 3=2}

正如你所看到的,有two students将达到最多的三个研讨会。

首先,我们使用实际集合更改了流中的所有学生对象,然后我们使用Collectors groupingBy()方法按大小对集合进行分组。

如果您只想获得学生人数,请使用以下代码:

students.stream()
    .map(Student::getSeminar)
    .collect(Collectors.groupingBy(Set::size, Collectors.counting()))
    .values().stream()
    .max(Comparator.comparing(a->a))
    .get();

你的输出将是:2


1
投票

在大多数实际情况中,您遍历列表两次的方法是最好的。它很简单,代码很容易理解。打击保存陈述的冲动 - 你不会按分号收取费用!

但是,当源数据无法遍历两次时,存在一些可想到的情况。也许它来自一些缓慢或一次性的来源,如网络流。

如果您遇到这种情况,您可能需要定义一个自定义收集器allMaxBy,它将所有max元素收集到下游收集器中。

然后你就可以写了

long maxCount = students.stream()
    .collect(allMaxBy(
            comparingInt(s -> s.getSeminar().size()),
            counting()
    ));

这是allMaxBy的一个实现:

public static <T, A, R> Collector<T, ?, R> allMaxBy(Comparator<? super T> cmp, Collector<? super T, A, R> downstream) {
    class AllMax {
        T val;
        A acc = null; // null means empty

        void add(T t) {
            int c = acc == null ? 1 : cmp.compare(t, val);
            if (c > 0) {
                val = t;
                acc = downstream.supplier().get();
                downstream.accumulator().accept(acc, t);
            } else if (c == 0) {
                downstream.accumulator().accept(acc, t);
            }
        }

        AllMax merge(AllMax other) {
            if (other.acc == null) {
                return this;
            } else if (this.acc == null) {
                return other;
            }
            int c = cmp.compare(this.val, other.val);
            if (c == 0) {
                this.acc = downstream.combiner().apply(this.acc, other.acc);
            }
            return c >= 0 ? this : other;
        }

        R finish() {
            return downstream.finisher().apply(acc);
        }
    }

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

0
投票

这很难看,但以下情况可行:

long count = students.stream()
    .filter(s -> s.getSeminar().size() == students
        .stream().mapToInt(a -> a.getSeminar().size())
        .max().orElse(0))
    .count();

说明:这会对学生列表进行流式处理并过滤学生,以便只有具有最大研讨会数量(这是嵌套的lambda是什么)的学生保留,然后记录该流的计数。


0
投票

很少修改@ Alex的解决方案,在进行分组时对键进行排序

    TreeMap<Integer, Long> agg = students.stream()
            .map(Student::getSeminar)
            .collect(Collectors.groupingBy(Set::size, TreeMap::new, Collectors.counting()));
    System.out.println(agg);
    System.out.println(agg.lastEntry().getKey() + " - " + agg.lastEntry().getValue());

产量

3 - 2
© www.soinside.com 2019 - 2024. All rights reserved.