将数据从文本文件存储到散列图而不是列表

Storing data from text file to hashmap instead of list

以下程序从格式为

的文本文件中读取和存储数据
1946-01-12;13:00:00;0.3;G
1946-01-12;18:00:00;-2.8;G
1946-01-13;07:00:00;-6.2;G
1946-01-13;13:00:00;-4.7;G
1946-01-13;18:00:00;-4.3;G
1946-01-14;07:00:00;-1.5;G
1946-01-14;13:00:00;-0.2;G

到数组列表。然后我将天气对象存储在另一个 class 中。第一种方法计算用户输入的两个日期之间的平均温度,第二种方法计算两个日期之间“G”:s 的百分比。

/**
 * Provides methods to retrieve temperature data from a weather station file.    
 */
public class WeatherDataHandler {
        private List<Weather> weatherData = new ArrayList<>();

        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);
                    weatherData.add(weather);       
                }
            }
    
            private List<String> parseData(String s) {
                return Arrays.asList(s.split(";"));
            }
        /**
         * Search for average temperature for all dates between the two dates (inclusive).
         * Result is sorted by date.
         */
        public Map<LocalDate, Double> avarageTemperatures(LocalDate dateFrom, LocalDate dateTo) {
            Map<LocalDate, Double> Averagetemperature = weatherData.stream().filter(weather -> !weather.getDate().isAfter(dateTo) && !weather.getDate().isBefore(dateFrom))
                    .collect(Collectors.groupingBy(Weather::getDate,
                            Collectors.averagingDouble(Weather::getTemperature)));
                    
            return Averagetemperature;}
    
        /**
         * Search for percentage of approved values between the two dates (inclusive).
         */
        public Double approvedValues(LocalDate dateFrom, LocalDate dateTo) {
            double percentageApproved = weatherData.stream().filter(weather -> !weather.getDate().isAfter(dateTo) && !weather.getDate().isBefore(dateFrom))
                    .mapToInt(obj -> obj.getQuality().equals("G") ? 1 : 0)
                    .summaryStatistics()
                    .getAverage();
            
            return percentageApproved;
        }   
    }

现在,我不想将映射实现到方法,而是想将文件中的数据存储到散列映射而不是列表(为了提高效率)。有没有简单的方法可以做到这一点而不必完全重做这些方法?我试过这个:

    public class WeatherDataHandler {
        public void loadData1(String filePath) throws IOException {
        List<String> fileData = Files.readAllLines(Paths.get(filePath));
        Map<LocalDate, List<Weather>> weatherData = new HashMap<LocalDate,List<Weather>>();{
    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(";"));
        }

但是如何在方法中访问地图的条目?

HashMaps 适用于键值对。如果不首先拆分然后迭代地将它们映射在一起,您不可能简单地将值存储在整个文本文件中。

哈希映射不适用于您的用例。 HashMap 可帮助您找到给定键的匹配值。例如,您可以制作一个 HashMap,为您提供给定一个日期的匹配天气数据。但是,您不能在不遍历日期范围的情况下使用 HashMap 来回答“给我这两个日期之间的所有天气数据”的查询。这就是您的 avarageTemperaturesapprovedValues 方法所需要的。

您可以使用 TreeMap。这将需要在几个地方更改您的程序。

变量声明:

private List<Weather> weatherData = new ArrayList<>();

必须变成:

private NavigableMap<LocalDate, List<Weather>> weatherData = new TreeMap<>();

这是一张“从日期到天气数据列表的地图”,因为每个日期有多个数据项。如果你能改变它,那就更简单了。

接下来,您需要使用:

而不是 weatherData.add(weather)
weatherData.computeIfAbsent(date, key -> new ArrayList<>()).add(weather);

同样,这更复杂,因为每个日期可能有不止一项。

最后,通过迭代访问数据的地方:

weatherData.stream().filter(weather -> !weather.getDate().isAfter(dateTo) && !weather.getDate().isBefore(dateFrom))

您可以利用 subMap 方法,它直接查找键范围:

weatherData.subMap(dateFrom, dateTo).values().stream().flatMap(List::stream)