Поместите сумму в качестве значения в хэш-карту - PullRequest
1 голос
/ 13 марта 2020

Мои два списка list2 и filetemp имеют одинаковую длину и содержат даты и температуры. Несколько элементов в списках показаны ниже:

[1946-01-12, 1946-01-12, 1946-01-12, 1946-01-13, 1946-01-13, 1946-01-13, 1946-01-14, 1946-01-14, 1946-01-14]
[-1.3, 0.3, -2.8, -6.2, -4.7, -4.3, -1.5, -0.2, -0.4]

Я хочу поместить их в хэш-карту с датами в качестве ключа и температурой в качестве значения. Поскольку у меня есть несколько значений температуры, соответствующих каждой дате, я хочу суммировать значения температуры для каждого дня (или, если возможно, рассчитать среднюю температуру для каждого дня), чтобы каждая дата на карте соответствовала средней температуре этой даты. Моя проблема сейчас в том, что моя карта выглядит так:

1946-01-12: -2.8
1946-01-13: -4.3
1946-01-14: -0.4

, поэтому вместо суммирования, например, -1,5 + (- 0,2) + (- 0,4) для даты 1946-01-14, она просто возвращает последнюю температуру этой даты. Кто-нибудь знает как это исправить?

public Map<LocalDate, Double> avarageTemperatures(LocalDate dateFrom, LocalDate dateTo) {
    List<LocalDate> list2 = new ArrayList<>();
    for (Weather weather : weatherData) {
        list2.add(weather.getDateTime());
    }

    Map<LocalDate, Double> map = new HashMap<>();
    List<Double> filetemp = new ArrayList<>();
    for (Weather weather : weatherData) {
        filetemp.add(weather.getTemperature());
    }
    Double val= 0.0;
    for (int i=1; i<list2.size(); i++) {
        if(list2.get(i)==list2.get(i-1)) {
            val+= filetemp.get(i);
            map.put(list2.get(i), val);
        } else {
            val=filetemp.get(i);
            map.put(list2.get(i), val);
        }
    }

    Set<Map.Entry<LocalDate, Double>> entrySet = map.entrySet();
    for(Map.Entry<LocalDate,Double> entry : entrySet) {
        if(!entry.getKey().isAfter(dateTo) && !entry.getKey().isBefore(dateFrom)) {
            System.out.println(entry.getKey()+": "+(entry.getValue()));
        }
    }

    return map;
}

Ответы [ 3 ]

2 голосов
/ 13 марта 2020

Хорошо, вот один из способов, используя streams и создавая карту карт. Внутренняя карта просто содержит температуры sum и average. List также можно было бы использовать, но карта позволяет индексировать символы c, чтобы упростить процесс.

Он работает следующим образом:

  • Используйте метод Collectors.teeing создать два потока. Первый делает частоту подсчета дат. Во-вторых, добавляет темпов. Оба заканчиваются на картах с датами в качестве ключей.
  • Затем вычислите среднюю температуру, разделив сумму на частоту подсчета дат. Это позволяет варьировать число дат для каждого образца и, тем не менее, получать точное среднее значение.
  • Как сумма температур, так и средняя температура сохраняются в виде карты.
  • A TreeMap используется для внешней карты для сортировки ключей в их естественном порядке.

    List<String> dates =
            List.of("1946-01-12", "1946-01-12", "1946-01-12",
                    "1946-01-13", "1946-01-13", "1946-01-13",
                    "1946-01-14", "1946-01-14", "1946-01-14");

    List<Double> temps = List.of(-1.3, 0.3, -2.8, -6.2, -4.7,
            -4.3, -1.5, -0.2, -0.4);

    Map<String,Map<String, Double>> data = IntStream
            .range(0,
                    dates.size())
            .boxed()
            .collect(Collectors.teeing(
                    Collectors.groupingBy(i -> dates.get(i),
                            Collectors.counting()),
                    Collectors.groupingBy(i -> dates.get(i),
                            Collectors.summingDouble(
                                    i -> temps.get(i))),
                    (counts, temp) -> temp.keySet().stream()
                            .collect(Collectors.toMap(k->k,
                                    k->Map.of("SUM", temp.get(k), "AVG",temp.get(k)
                                            / counts.get(k)), (m,n)->n, TreeMap::new))));



    for (String k : data.keySet())  {
        System.out.printf("For %s - sum of temperatures was %6.3f%n",k,data.get(k).get("SUM"));
        System.out.printf("For %s - average temp was %6.3f%n",k,data.get(k).get("AVG"));
        System.out.println();
     }

Он печатает следующее:

For 1946-01-12 - sum of temperatures was -3.800
For 1946-01-12 - average temp was -1.267

For 1946-01-13 - sum of temperatures was -15.200
For 1946-01-13 - average temp was -5.067

For 1946-01-14 - sum of temperatures was -2.100
For 1946-01-14 - average temp was -0.700


1 голос
/ 13 марта 2020

Это один из способов сделать это. Чтобы получить список объектов Weather, таких как у вас, мы создаем список объектов Weather, используя массив String и массив значений Double. Из этого списка мы просто собираем, используя Collectors # groupingBy, который позволяет нам определить ключ, по которому мы хотим сгруппировать, который в данном случае является LocalDate, и Collector используется для группировки всех соответствующих значений ключа вместе, который в этом случае является Collectors # summingDouble, так как мы хотим суммировать все двойные значения.

        String[] dates = {
                "1946-01-12", "1946-01-12", "1946-01-12", "1946-01-13", "1946-01-13", "1946-01-13",
                "1946-01-14", "1946-01-14", "1946-01-14"
        };

        double[] temperatures = {-1.3, 0.3, -2.8, -6.2, -4.7, -4.3, -1.5, -0.2, -0.4};

        class Weather {

            private final LocalDate date;

            private final double temperature;

            Weather(LocalDate date, double temperature) {
                this.date = date;
                this.temperature = temperature;
            }

            public LocalDate getDate() {
                return date;
            }

            public double getTemperature() {
                return temperature;
            }
        }

        List<Weather> weather = IntStream.range(0, dates.length)
                .mapToObj(index -> new Weather(LocalDate.parse(dates[index]), temperatures[index]))
                .collect(Collectors.toList());        

       Map<LocalDate, Double> temperaturesSum = weather.stream()
                .collect(Collectors.groupingBy(Weather::getDate,
                        Collectors.summingDouble(Weather::getTemperature)));

        Map<LocalDate, Double> temperaturesAverage = weather.stream()
                .collect(Collectors.groupingBy(Weather::getDate,
                        Collectors.averagingDouble(Weather::getTemperature)));

        System.out.println("sum: " + temperaturesSum);
        System.out.println("average: " + temperaturesAverage);

Вывод

sum: {1946-01-12=-3.8, 1946-01-13=-15.2, 1946-01-14=-2.1}
average: {1946-01-12=-1.2666666666666666, 1946-01-13=-5.066666666666666, 1946-01-14=-0.7000000000000001}
0 голосов
/ 13 марта 2020

Надеюсь, это поможет:

    List<String> dates = Arrays.asList("1946-01-12", "1946-01-12", "1946-01-12", "1946-01-13", "1946-01-13", "1946-01-13", "1946-01-14", "1946-01-14", "1946-01-14");
    List<Double> values = Arrays.asList(-1.3, 0.3, -2.8, -6.2, -4.7, -4.3, -1.5, -0.2, -0.4);

    Map<String, DoubleSummaryStatistics> res = IntStream
            .range(0, dates.size())
            .boxed()
            .map(index -> new Pair<>(dates.get(index), values.get(index)))
            .collect(groupingBy(Pair::getKey,
                    summarizingDouble(Pair::getValue)));

    System.out.println(res);

и результат:

{1946-01-14=DoubleSummaryStatistics{count=3, sum=-2.100000, min=-1.500000, average=-0.700000, max=-0.200000}, 
1946-01-12=DoubleSummaryStatistics{count=3, sum=-3.800000, min=-2.800000, average=-1.266667, max=0.300000}, 
1946-01-13=DoubleSummaryStatistics{count=3, sum=-15.200000, min=-6.200000, average=-5.066667, max=-4.300000}}
...