Как добавить значения в карту дублированных ключей в Java 8

#java #collections

#java #Коллекции

Вопрос:

Я хочу добавить значения в карту дублированных ключей в Java 8.

В качестве примера:

Например: если strArr ["B:-1", "A:1", "B:3", "A:5"] , то моя программа должна вернуть строку A:6,B:2 .

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

Ввод: new String[] {"X:-1", "Y:1", "X:-4", "B:3", "X:5"}

Вывод: B:3,Y:1

Ввод: new String[] {"Z:0", "A:-1"}

Вывод: A:-1

Пробный код:

 public static String Output(String[] strArr) {
       //strArr = new String[] {"X:-1", "Y:1", "X:-4", "B:3", "X:5"};
        Map<String, Double> kvs =
                Arrays.asList(strArr)
                    .stream()
                    .map(elem -> elem.split(":"))
                    .collect(Collectors.toMap(e -> e[0], e -> Double.parseDouble(e[1])));
        
        kvs.entrySet().forEach(entry->{
            System.out.println(entry.getKey()   " "   entry.getValue());  
         });
        
        return strArr[0];
      }
 

Ошибка:

Исключение в потоке «main» java.lang.Исключение IllegalStateException: дубликат ключа -1.0

Как я могу это исправить?

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

1. Вы добавляете те же ключи в map при создании своей карты. Просто замените свой Map на List<Pair> .

2. Как я могу избежать этого и решить эту проблему

3. Вы не можете добавлять дублированные ключи в карту. Только с заменой предыдущего значения.

4. Можете ли вы предложить мне решить эту проблему

5. Вы можете использовать Map::compute для изменения текущего значения (неважно, существует ключ или нет).

Ответ №1:

Вы должны объявить стратегию слияния в первом потоке:

 .collect(Collectors.toMap(e -> e[0], e -> Double.parseDouble(e[1]), Double::sum));
 

а затем отфильтровать карту по нулевому значению:

   .filter(s-> s.getValue() != 0)
 

для сортировки по использованию ключа:

    .sorted(Map.Entry.comparingByKey())
 

код результата:

    String [] strArr = new String[] {"X:-1", "Y:1", "X:-4", "B:3", "X:5"};
    Map<String, Double> kvs =
            Arrays.asList(strArr)
                    .stream()
                    .map(elem -> elem.split(":"))
                    .collect(Collectors.toMap(e -> e[0], e -> Double.parseDouble(e[1]), Double::sum));

    kvs.entrySet().stream()
            .filter(s-> s.getValue() != 0)
            .sorted(Map.Entry.comparingByKey())
            .forEach(entry->{
        System.out.println(entry.getKey()   " "   entry.getValue());w
    });
 

Ответ №2:

Это работает для меня, я использовал Integer вместо double и summaringInt() function для значений суммы с тем же ключом:

         String[] strArr = new String[] { "X:-1", "Y:1", "X:-4", "B:3", "X:5" };

    Map<String, IntSummaryStatistics> collect = Arrays.asList(strArr)
        .stream()
        .map(elem -> elem.split(":"))
        .collect(Collectors.groupingBy(e -> e[0], Collectors.summarizingInt(e -> Integer.parseInt(e[1]))));

    System.out.println("Result:");

    collect.entrySet().stream()
        .filter(e -> e.getValue().getSum() != 0)
        .sorted(Map.Entry.comparingByKey())
        .forEach(e -> System.out.println("Key : "   e.getKey()   ", Value : "   e.getValue().getSum()));
 

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

1. Collectors.summingInt тоже должно получиться

Ответ №3:

Также можно использовать Collectors.groupingBy Collectors.summingDouble для создания отсортированной kvs карты путем сбора в TreeMap :

 String [] strArr = new String[] {"X:-1", "Y:1", "X:-4", "B:3", "X:5"};
Map<String, Double> kvs = Arrays.stream(strArr)
        .map(elem -> elem.split(":"))
        .collect(Collectors.groupingBy(
            e -> e[0], 
            TreeMap::new, // sort by key
            Collectors.summingDouble(e -> Double.parseDouble(e[1]))
        ));
System.out.println(kvs);  // entries with 0 value yet to be removed
// output
// {B=3.0, X=0.0, Y=1.0}
 

Если требуется просто распечатать карту в указанном формате без значений 0, это можно сделать следующим образом:

 System.out.println(
    kvs.entrySet().stream()
        .filter(e -> e.getValue() != 0)
        .map(e -> new StringBuilder(e.getKey()).append(':').append(e.getValue().intValue()) )
        .collect(Collectors.joining(","))
);
// output
// B:3,Y:1
 

Если необходимо удалить значения 0 из kvs , a removeIf может быть применено к его набору записей:

 kvs.entrySet().removeIf(e -> e.getValue() == 0);
System.out.println(kvs);
// output
// {B=3.0, Y=1.0}