Есть ли какой-нибудь простой способ объединить набор значений, когда мы преобразуем ключ карты в нижний регистр в Java?

#java #collections #java-stream

Вопрос:

У меня есть карта со смешанными случаями, например

 {a=[v1, V1], A={v2, V2, v3} 
 

Я бы хотел, чтобы все было в нижнем регистре,

 {a=[v1, v2, v3]}
 

Я сделал это многословно на Java, задаваясь вопросом, есть ли какой-нибудь простой/лучший способ. Спасибо

 Map<String, Set<String>> result = new HashMap<>();

for (Map.Entry<String, Set<String>> entry : map.entrySet()) {
    String key = entry.getKey().toLowerCase();
    Set<String> currSet = entry.getValue().stream().map(v -> v.toLowerCase()).collect(Collectors.toSet());

    Set<String> existSet = result.get(key);

    if (existSet == null) {
        result.put(key, currSet);
    } else {
        existSet.addAll(currSet);
    }
}
 

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

1. Я уверен, что вы можете сделать это с помощью одного потока без дополнительных шагов.

Ответ №1:

Вы можете использовать putIfAbsent() или computeIfAbsent() предотвратить ненужное создание экземпляра набора на карте , чтобы создать новый набор, если значения еще нет, а затем просто позвонить addAll()

 Map<String, Set<String>> result = new HashMap<>();

for (Map.Entry<String, Set<String>> entry : map.entrySet()) {
    String key = entry.getKey().toLowerCase();
    Set<String> currSet = entry.getValue().stream().map(v -> v.toLowerCase()).collect(Collectors.toSet());

    result.computeIfAbsent(key, k -> new HashSet<>()).addAll(currSet);
}
 

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

 result.putIfAbsent(key, new HashSet<>()).addAll(currSet);
 

Ответ №2:

В случае, если вы являетесь поклонником java-потока:

     @Test
    void mapToMap() {
        // Map.of: Java 9 or higher
        Map<String, Set<String>> before = Map.of("A", Set.of("A", "a"), "a", Set.of("b", "B", "c"));
        
        // Collectors.toMap: Java 8 or higher
        Map<String, Set<String>> after = before.entrySet().stream().collect(
                Collectors.toMap(
                        e -> e.getKey().toLowerCase(),
                        e -> e.getValue().stream().map(String::toLowerCase).collect(Collectors.toSet()),
                        (existing, replacement) -> {
                            existing.addAll(replacement);
                            return existing;
                        }
                )
        );
        assertThat(after.size()).isEqualTo(1);
        assertThat(after.get("a")).containsExactly("a", "b", "c");
    }
 

Ответ №3:

Вы можете использовать Map.computeIfAbsent() вот так.

 public static void main(String[] args) throws IOException {
    Map<String, Set<String>> input = Map.of(
        "a", Set.of("v1", "V1"),
        "A", Set.of("v2", "V2", "v3"));

    Map<String, Set<String>> output = new LinkedHashMap<>();
    for (Entry<String, Set<String>> e : input.entrySet())
        output.computeIfAbsent(e.getKey().toLowerCase(), k -> new HashSet<>())
            .addAll(e.getValue().stream().map(String::toLowerCase).toList());

    System.out.println(output);
}
 

выход:

 {a=[v1, v2, v3]}