#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}