Список потоков java<Карта> требуется среднее значение на основе строки

#java #list #dictionary #filter #java-stream

#java #Список #словарь #Фильтр #java-stream

Вопрос:

Мне нужно среднее значение по списку

     List<Measurement> measurements = new ArrayList<>();

    Measurement m1 = new Measurement();
    Map<String,Double> map1 = new HashMap<>();
    map1.put("age",18.0);
    map1.put("score",88.0);
    map1.put("rating",5.0);
    m1.setMetric(map1);

    Measurement m2 = new Measurement();
    Map<String,Double> map2 = new HashMap<>();
    map2.put("age",21.0);
    map2.put("score",null);
    map2.put("rating",23.0);
    m2.setMetric(map2);

    Measurement m3 = new Measurement();
    Map<String,Double> map3 = new HashMap<>();
    map3.put("age",31.0);
    map3.put("score",32.0);
    map3.put("rating",null );
    m3.setMetric(map3);

    measurements.add(m1);
    measurements.add(m2);
    measurements.add(m3);
  

Как мне получить средний возраст для приведенного выше списка карт. Также усредняйте оценку, игнорируя значения null.

Любая помощь была бы действительно оценена. Я пытаюсь исправить это уже 3 дня. Заранее благодарю вас.

Комментарии:

1. Можете ли вы поделиться Measurement объектом?

Ответ №1:

Вы можете получить среднее значение возраста как:

 Double averageAge = measurements.stream()
        .flatMap(a -> a.getMetric().entrySet().stream())
        .filter(a -> a.getKey().equals("age"))
        .mapToDouble(Map.Entry::getValue)
        .average()
        .orElse(Double.NaN);
  

и аналогично, для усреднения оценки потребуется дополнительное условие фильтра для исключения null значений.

Комментарии:

1. Я думаю, вам не обязательно использовать filter . Это может выглядеть как .mapToDouble(map -> map.get("age"))

2. @Ruslan сделал это общим, учитывая случай с null значениями баллов в другом вычислении.

3. Если вы хотите избежать нулей, просто добавьте .filter(Objects::nonNull) .

4. Вы можете использовать .map(a -> a.getMetric()) .flatMapToDouble(m -> m.containsKey("age")? DoubleStream.of(m.get("age")): DoubleStream.empty()) . Кроме того, нет причин помещать результат в Double вместо простого использования double .

Ответ №2:

для такого Measurement класса:

 class Measurement {

    Map<String, Double> map;

    public void setMetric(Map<String, Double> map) {
        this.map = map;
    }
}
  

Как определить средний «возраст» (используя stream):

 Double averageAge = measurements.stream()
        .collect(Collectors.averagingDouble(node -> node.map.getOrDefault("age", 0D)));
  

И поток для обнуляемого «балла»:

Как найти среднее значение «age» (используя stream) с проверкой null:

 Double averageAge = measurements.stream()
        .filter(node -> node.map.get("score") != null)
        .collect(Collectors.averagingDouble(node -> node.map.getOrDefault("score", 0D)));
  

В приведенном выше коде у вас есть, node.map где map — класс формы поля. Может быть заменен на getMap() или другой метод, возвращающий значение (которое вы задаете setMetric() )

Как найти среднее значение «возраст» (используя цикл):

 Double average = 0D;
for (Measurement measure : measurements) {
    average  = measure.map.getOrDefault("age", 0D);
}
average /= measurements.size();
  

Как найти среднее значение «score» (используя цикл) с проверкой null:

 Double average = 0D;
int counter = 0;
for (Measurement measure : measurements) {
    if (measure.map.get("score") != null) {
        average  = measure.map.getOrDefault("score", 0D);
        counter  ;
    }
}
average /= counter;
  

Как найти наименьший «результат» (используя цикл) с проверкой null:

 Double min = Double.MAX_VALUE;

for (Measurement measure : measurements) {
    Double score = measure.map.get("score");
    if (score != null amp;amp; score < min) {
        min = score;
    }
}

System.out.println(min);
  

Как найти наибольший «возраст» (используя потоки)

 Double max = measurements.stream()
        .filter(node -> node.map.get("score") != null)
        .mapToDouble(node -> node.map.get("score"))
        .max()
        .orElse(0.0);
  

Комментарии:

1. Большое спасибо за ваш быстрый ответ. 🙂 действительно ценится. Также мне нужно среднее значение для ‘score’, которое имеет нулевые значения. Для этого я получаю нулевой указатель. Пожалуйста, помогите мне в этом

2. что мне нужно, так это — Если есть значение null; просто игнорируйте это; и не добавлять среднее значение. Например: значение 1: 10, значение 2: null, значение 3: 30 — тогда среднее значение равно (value1 value3) / 2. Не (value1 value3)/3

3. Это подходит мне больше; но если бы хотелось иметь максимальное или минимальное значение вместо среднего? Пожалуйста, дайте мне знать

4. @Hruday добавил минимальное и максимальное значения.

Ответ №3:

Вы можете вычислить средние значения для каждого ключа карты, используя:

 Map<String, Double> result = Stream.of(m1, m2, m3)
        .flatMap(m -> m.getMap1().entrySet().stream()
                       .filter(e -> e.getValue() != null))
        .collect(Collectors.groupingBy(e -> e.getKey(), 
                Collectors.averagingDouble(e -> e.getValue())));
  

И выходные данные для ваших тестовых данных будут {score=60.0, rating=14.0, age=23.333333333333332}

Комментарии:

1. Спасибо; Что, если бы я хотел иметь максимальное значение вместо среднего? Не могли бы вы, пожалуйста, дать мне знать

2. @Hruday Вы можете использовать Collectors.maxBy вместо averagingDouble . Но потребуется некоторая очистка, чтобы избавиться от Optional значений in.

3. ИМХО, код становится более читаемым при перемещении .filter(e -> e.getValue() != null) из функции, переданной в flatMap , на следующий шаг другого потока.