#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
, на следующий шаг другого потока.