如何使用Stream改进此List迭代?

Way*_*eio 5 java lambda java-8 java-stream

我正在尝试计算在“对象列表”中的字段中看到一个Int的次数。

这是我的代码

TreeMap<Integer, Double> ratings = new TreeMap();
ArrayList<Establishment> establishments = new ArrayList<>();

double one = 0;
double two = 0;
double three = 0;
double five = 0;

for (Establishment e : establishments) {
    if (e.getRating() == 1) {
        one++;
    }
    if (e.getRating() == 2) {
        two++;
    }
    if (e.getRating() == 3) {
        three++;
    }
    if (e.getRating() == 5) {
        five++;
    }
}

    ratings.put(1, (one / establishments.size()) * 100);
    ratings.put(2, (two / establishments.size()) * 100);
    ratings.put(3, (three / establishments.size()) * 100);
    ratings.put(5, (five / establishments.size()) * 100);
Run Code Online (Sandbox Code Playgroud)

但这并不理想,如果添加更多的评分(例如20+),则会创建大量的双打,并且无法维护。

我知道如果我有一个整数列表,我可以对Stream进行操作

listOfInts.stream().filter(i -> i == 3).count()
Run Code Online (Sandbox Code Playgroud)

但这是一个对象列表,其中包含一个int,我需要计算该对象列表中的评级数量==X。

所以我需要的伪代码:

Establishmentemnts.getAllRatings()。stream()。filter(ratings-> rating == 3).count()*

*对每种评级类型1-5重复

**没有getAllRatings-我想这就是我要解决的问题)

GBl*_*ett 5

你可以做:

Map<Integer, Double> ratings = new TreeMap<>();
List<Establishment> establishments = new ArrayList<>();
establishments.stream() 
              .collect(Collectors.groupingBy(Establishment::getRating, Collectors.counting()))
              .forEach((k, v) -> ratings.put(k, (double)v/establishments.size() * 100));
Run Code Online (Sandbox Code Playgroud)

Collectors::groupingBy与配合使用Collectors::counting,将创建一个Map由评分计数组成的内容,然后将forEach其添加到TreeMap

或者,按照VGR的建议,可以更优雅地使用Collectors::collectingAndThen

Map<Integer, Double> ratings =
establishments.stream()
              .collect(
                       Collectors.groupingBy(Establishment::getRating, 
                       Collectors.collectingAndThen(Collectors.counting(), c -> c * 100.0 / establishments.size())
               ));
Run Code Online (Sandbox Code Playgroud)

它将直接创建,Map而无需创建Map,再次对其进行流式处理,然后Map再次收集


小智 5

仅使用或多或少的流:

List<Establishment> establishments = new ArrayList<>();
Map<Integer, Double> ratings = establishments.stream()
        .collect(Collectors.groupingBy(Establishment::getRating, Collectors.counting()))
        .entrySet()
        .stream()
        .collect(Collectors.toMap(e -> e.getKey(), 
                                  e -> 100.0 * (e.getValue() / establishments.size())));
Run Code Online (Sandbox Code Playgroud)


Aar*_*esh 3

以下是如何使用流来实现 getAllRatings 来获取评级列表

List<Integer> attributes = establishments.stream().map(es -> es.getRating()).collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

因此,要获取特定评级的评级计数,您可以使用

establishments.stream().map(es -> es.getRating()).collect(Collectors.toList()).stream().filter(ratings -> ratings == 3).count()
Run Code Online (Sandbox Code Playgroud)

如果您想获取所有评级的评级计数/百分比,请使用@Marek 的答案中的代码