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

时间:2019-03-10 19:33:00

标签: 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);

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

我知道,如果我有一个整数列表,我可以用Stream做些什么

listOfInts.stream().filter(i -> i == 3).count()

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

那么我需要的伪代码:

  

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

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

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

5 个答案:

答案 0 :(得分: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));

Collectors::groupingByCollectors::counting一起使用,这将创建一个由评分计数组成的Map,然后使用forEach将它们添加到{{1} }

或者,如VGR建议的那样,更优雅地使用Collectors::collectingAndThen

TreeMap

这将直接创建Map<Integer, Double> ratings = establishments.stream() .collect( Collectors.groupingBy(Establishment::getRating, Collectors.collectingAndThen(Collectors.counting(), c -> c * 100.0 / establishments.size()) )); ,而无需创建Map,再次对其进行流式处理,然后再次收集到Map

答案 1 :(得分: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())));

答案 2 :(得分:3)

在这里,您可以使用流来实现getAllRatings以获得评分列表

List<Integer> attributes = establishments.stream().map(es -> es.getRating()).collect(Collectors.toList());

因此,可以使用特定等级的等级计数

establishments.stream().map(es -> es.getRating()).collect(Collectors.toList()).stream().filter(ratings -> ratings == 3).count()

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

答案 3 :(得分:0)

要获取a,可以将流api与groupingBysummingDouble一起用作下游:

1 <= a < 9

并计算次数:

TreeMap<Integer, Double> ratings

答案 4 :(得分:-1)

循环中,您可以求和值:

for (Establishment e : establishments) {
    // Get old value OR set to "0"
    Double rating = ratings.getOrDefault(e.getRating(), 0);
    // increase rating (counter)
    ratings.put(e.getRating(), rating + 1);
}

最后计算平均值:

// Calculate part of equation which is not changing in loop
int size = establishments.size() * 100;

for (Map.Entry<Integer, Double> entry : ratings.entrySet()) {
    // Calculate average
    Double average = entry.getValue() / size;
    // Add it to the map
    ratings.put(entry.getKey(), average);
}