Home > Back-end >  Is there any simple way to merge value set when we convert key of map to lower case in Java?
Is there any simple way to merge value set when we convert key of map to lower case in Java?

Time:10-21

I have a map with mixed cases, e.g.

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

I'd like to make everything to lowerCase,

{a=[v1, v2, v3]}

I did it verbosely in Java, wondering whether is any simple/better way. Thanks

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);
    }
}

CodePudding user response:

You could utilize putIfAbsent(), or computeIfAbsent() to prevent an unnecessary instantiation of a set, on the map to create a new set if there isn't a value yet, and then just call 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() is similar, but again, it will always instantiate a new HashSet instead of only instantiating one if the value is actually absent:

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

CodePudding user response:

In case you are a java-stream fan:

    @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");
    }

CodePudding user response:

You can use Map.computeIfAbsent() like this.

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);
}

output:

{a=[v1, v2, v3]}
  • Related