Подсчет значений карты - PullRequest
2 голосов
/ 09 июля 2020

Следующая карта содержит данные в форме:

1946-01-12;13:00:00;0.3;G
1946-01-12;18:00:00;-2.8;Y
1946-01-13;07:00:00;-6.2;G
1946-01-13;13:00:00;-4.7;G

Даты являются ключами.

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.NavigableMap;
import java.util.TreeMap;

public class WeatherDataHandler {
    private NavigableMap<LocalDate, List<Weather>> weatherData =
            new TreeMap<>();
    
    public void loadData(String filePath) throws IOException {
        List<String> fileData =
                Files.readAllLines(Paths.get(filePath));
        for (String str : fileData) {
            List<String> parsed = parseData(str);
            LocalDate date = LocalDate.parse(parsed.get(0));
            LocalTime time = LocalTime.parse(parsed.get(1));
            double temperature = Double.parseDouble(parsed.get(2));
            String quality = parsed.get(3);
            Weather weather =
                    new Weather(date, time, temperature, quality);
            
            List<Weather> entries;
            entries = new ArrayList<Weather>();
            if (weatherData.get(date) == null) {
                entries.add(weather);
                weatherData.put(date, entries);
            } else {
                entries = weatherData.get(date);
                entries.add(weather);
            }
        }
    }
    
    private List<String> parseData(String str) {
        return Arrays.asList(str.split(";"));
    }
}

Теперь я хочу реализовать метод, который подсчитывает количество записей каждого ключа, или, другими словами, количество раз, когда каждая дата встречается в списке. Он должен возвращать все даты между двумя датами (то есть вводимые пользователем) и количество значений каждого ключа. Я начал со следующего кода

/**
 * Search for missing values between the two dates (inclusive) assuming there
 * should be 24 measurement values for each day (once every hour). Result is
 * sorted by date.
 */
public Map<LocalDate, Integer> missingValues(LocalDate dateFrom, LocalDate dateTo) {

    Map<LocalDate, Integer> counts = weatherData.subMap(dateFrom , dateTo)
            .values().stream()
            .flatMap(List::stream)
            .filter(p -> p.getValue()
            .collect(Collectors.toMap(p -> p.getKey(), p -> p.getValue()));
    }
}

, но у меня проблемы с методом фильтров и сборщиков. Как мне завершить sh это?

Ответы [ 3 ]

1 голос
/ 09 июля 2020

Используйте Collectors.groupingBy для группировки по дате Weather класса и Collectors.counting() для подсчета размера каждой группы.

Map<LocalDate, Long> counts = weatherData.subMap(dateFrom ,dateTo)
                                         .values()
                                         .stream()
                                         .flatMap(List::stream)
                        .collect(Collectors.groupingBy(p -> p.getDate(), Collectors.counting()));
0 голосов
/ 10 июля 2020

Поскольку вы используете потоки для упрощения кода, вы также можете сделать следующее.

Вместо того, чтобы делать

    List<Weather> entries;
    entries = new ArrayList<Weather>();
    if (weatherData.get(date) == null) {
         entries.add(weather);
         weatherData.put(date, entries);
    } else {
        entries = weatherData.get(date);
        entries.add(weather);
    }

Вы можете просто сделать

     weatherData.computeIfAbsent(date, k->new ArrayList<>()).add(weather);

Он говорит, что если ключа date нет, введите новый ArrayList в качестве значения. В любом случае верните value. Поскольку значение - это list, которое было либо только что введено, либо уже есть, вы можете просто добавить экземпляр weather в список.

Компилятор уже знает тип списка, поскольку он получил это из ваш экземпляр NavigableMap.

Если вы хотите сначала проверить его, попробуйте этот простой пример.

Map<Integer,List<Integer>> map = new HashMap<>();
System.out.println(map);
map.computeIfAbsent(10, k-> new ArrayList<>()).add(20);
System.out.println(map);
map.computeIfAbsent(10, k-> new ArrayList<>()).add(30);
System.out.println(map);

computeIfAbsent доступен с Java 1.8

0 голосов
/ 09 июля 2020

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

Для этого вам нужно будет использовать Collectors.groupingBy при сборе карты. а для значения это будет просто Collectors.counting(). Пожалуйста, проверьте фрагмент кода ниже, чтобы получить более подробную информацию:

Map<LocalDate, Long> countMap = weatherData
                                .subMap(dateFrom ,dateTo)
                                .values()
                                .stream()
                                .flatMap(List::stream)
                                .collect(Collectors.groupingBy(p -> p.getDate(), Collectors.counting()));
...