BlueDolphin
BlueDolphin

Reputation: 9765

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

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

Upvotes: 0

Views: 112

Answers (3)

user17201277
user17201277

Reputation:

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

Upvotes: 1

Linh Vu
Linh Vu

Reputation: 970

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

Upvotes: 2

TheNytangel
TheNytangel

Reputation: 546

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

Upvotes: 2

Related Questions