🚀

ReverseMap

2022/09/14に公開

これは何ですか?

Mapのキーと値を入れ替えます。値が重複していたらどれか一つになります。
情報の欠落しないMap<V, Set<K>>版もありますが使いづらいです。
Collectors.toMap、Collectors.groupingByがnullを扱わないので改良。

ソースコード

import java.util.AbstractMap;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

public class ReverseMap<K, V> extends AbstractMap<V, K> {

    private final Map<V, K> map;

    public ReverseMap(Map<K, V> map) {
        this.map = map.entrySet().stream()
                .map(e -> Collections.singletonMap(e.getValue(), e.getKey()))
                .collect(HashMap::new, Map::putAll, Map::putAll);
    }

    @Override
    public Set<Entry<V, K>> entrySet() {
        return map.entrySet();
    }

    public static <K, V> Map<V, Set<K>> reverse(Map<K, V> map) {
        return map.entrySet().stream()
                .collect(Collectors.groupingBy(
                        e -> Optional.ofNullable(e.getValue()),
                        Collectors.mapping(Entry::getKey, Collectors.toSet())))
                .entrySet().stream()
                .collect(Collectors.toMap(e -> e.getKey().orElse(null), Entry::getValue));
    }
}

使用例

Map<Integer, String> map = new HashMap<>();
map.put(1, "A");
map.put(2, "B");
map.put(3, "C");
map.put(4, "A");
map.put(5, "B");
map.put(6, "C");
System.out.println(new ReverseMap<>(map));
// => {A=4, B=5, C=6}
System.out.println(ReverseMap.reverse(map));
// => {A=[1, 4], B=[2, 5], C=[3, 6]}
map.put(7, null);
map.put(8, null);
map.put(null, "C");
System.out.println(new ReverseMap<>(map));
// => {null=8, A=4, B=5, C=6}
System.out.println(ReverseMap.reverse(map));
// => {null=[7, 8], A=[1, 4], B=[2, 5], C=[null, 3, 6]}

Discussion