Как создать карту с суммой всех конкретных объектов?

#java #collections #java-8 #java-stream

Вопрос:

У меня есть объект:

 class Sample
{
    String currency;
    String amount;
}
 

Мне нужна выходная карта с суммой всех объектов определенной валюты.

Пример-

  • INR 40
  • 80 долларов США
  • 20 ЕВРО

Указатель. Я работал со следующим кодом, но он работает не так, как я ожидал. Вы можете использовать этот код в качестве ссылки:

 Map<String, Double> finalResult = samples
        .stream()
        .collect(Collectors.toMap(
                Sample::getCurrency,
                e -> e.getAmount()
                      .stream()
                      .sum()));
 

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

1. Не уверен, в чем заключается ваш реальный вопрос. «Возможное решение» звучит так, как будто у вас уже есть ответ? Если у вас возникли проблемы, пожалуйста, добавьте их в вопрос.

2. @Марвин : Это скорее указатель на решение. Что-то, что я пробовал, но не получилось полностью.

Ответ №1:

Вам нужно использовать groupingBy с summingDouble и не toMap :

 Map<String, Double> finalResult = samples
        .stream()
        .collect(Collectors.groupingBy(
                Sample::getCurrency,
                Collectors.summingDouble(Sample::getAmount)
        ));
 

Я считаю, что сумма имеет тип Double , и ваш пример неверен ( String amount; )

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

1. Хороший ответ, так что 1. Однако toMap работает с третьим аргументом Double::sum , который я продемонстрировал в своем альтернативном ответе.

2. хороший @WJS, я не знал об этом раньше

Ответ №2:

Просто хотел предложить следующую альтернативу для дальнейшего рассмотрения. Я также предполагаю, что вы имели double в виду сумму, а также наличие соответствующих получателей. Вы могли бы использовать Collectors.toMap , если бы включили a merge function . Похоже, у вас была правильная идея, но неправильный синтаксис.

 List<Sample> samples =
                List.of(new Sample("USD", 10), new Sample("USD", 30),
                        new Sample("INR", 40), new Sample("INR", 90),
                        new Sample("EUR", 20), new Sample("EUR", 50));
 

Третий аргумент toMap -это a merge function для правильной обработки дубликатов. В этом случае он вычисляет сумму значений для каждого ключа по мере их обнаружения.

 Map<String, Double> result = samples.stream()
           .collect(Collectors.toMap(
                 Sample::getCurrency, Sample::getAmount, Double::sum));

result.entrySet().forEach(System.out::println);
 

С принтами

 EUR=70.0
USD=40.0
INR=130.0
 

Если вы действительно хотите , чтобы ваш класс хранил сумму как a String , вы можете Sample::getAmount заменить sample->Double.valueOf(sample.getAmount()) ее на преобразование String в a Double . Но поскольку вы, вероятно, будете повторно использовать эти значения в вычислениях, имо, лучше всего хранить сумму в наиболее часто используемой форме при создании экземпляров класса.

Ответ №3:

 Map<String, Double> finalResult = samples.stream().collect(
    Collectors.groupingBy(
          (Sample::getCurrency),
          Collectors.summingDouble(
             sample -> { return Double.parseDouble(sample.getAmount()); 
})));
 

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

1.ввод : ( INR 40 USD 80 EUR 20), (INR 0 USD 100 EUR 100 ) </br> </br>результат {EUR=120.0, USD=180.0, INR=40.0}