Java invert map

2019-01-09 08:31发布

I need create inverse map - select unique values and for them find keys. Seems that only way is to iterate all key/value pairs, because entrySet returns set of so value not unique? Thanks.

标签: java map invert
8条回答
孤傲高冷的网名
2楼-- · 2019-01-09 09:09

Seems that only way is to iterate all key/value pairs, because entrySet returns set of so value not unique?

It's one way at least. Here's an example:

Map<Integer, String> map = new HashMap<Integer, String>();

map.put(1, "one");
map.put(2, "two");

Map<String, Integer> inverted = new HashMap<String, Integer>();

for (Integer i : map.keySet())
    inverted.put(map.get(i), i);

In case of non-unique values, this algorithm will map the last value found to it's key. (Since the iteration order is undefined for most maps, this should be as good as any solution.)

If you really do want to keep the first value found for each key, you could change it to

if (!inverted.containsKey(map.get(i)))
    inverted.put(map.get(i), i);
查看更多
太酷不给撩
3楼-- · 2019-01-09 09:11

I would give another approach to this problem giving an extra dimension: duplicate values in EntrySet.

public static void main(String[] args) {

    HashMap<Integer, String> s = new HashMap<Integer, String>();
    s.put(1, "Value1");
    s.put(2, "Value2");
    s.put(3, "Value2");
    s.put(4, "Value1");

    /*
     * swap goes here
     */
    HashMap<String,List<Integer>> newMap = new HashMap<String, List<Integer>>();
    for (Map.Entry<Integer, String> en : s.entrySet()) {
        System.out.println(en.getKey() + " " + en.getValue());

        if(newMap.containsKey(en.getValue())){
            newMap.get(en.getValue()).add(en.getKey());
        } else {
            List<Integer> tmpList = new ArrayList<Integer>();
            tmpList.add(en.getKey());
            newMap.put(en.getValue(), tmpList);
        }
    }

    for(Map.Entry<String, List<Integer>> entry: newMap.entrySet()){
        System.out.println(entry.getKey() + " " + entry.getValue());
    }
}

T result will be that:

1 Value1
2 Value2
3 Value2
4 Value1
Value1 [1, 4]
Value2 [2, 3]

查看更多
可以哭但决不认输i
4楼-- · 2019-01-09 09:12

Take a look at Google Guava BiMap.

Example usage

Map<Integer, String> map = new HashMap<>();
map.put(1, "one");
map.put(2, "two");

Map<String, Integer> inverted = HashBiMap.create(map).inverse();
查看更多
Emotional °昔
5楼-- · 2019-01-09 09:15

To get an inverted form of a given map in java 8:

public static <K, V> Map<V, K> inverseMap(Map<K, V> sourceMap) {
    return sourceMap.entrySet().stream().collect(
        Collectors.toMap(Entry::getValue, Entry::getKey,
           (a, b) -> a) //if sourceMap has duplicate values, keep only first
        );
}

Example usage

Map<Integer, String> map = new HashMap<Integer, String>();

map.put(1, "one");
map.put(2, "two");

Map<String, Integer> inverted = inverseMap(map);
查看更多
Melony?
6楼-- · 2019-01-09 09:16

Apache Commons Collections also provides a BidiMap interface for bi-directional maps, along with several implementations.

BidiMap JavaDoc

查看更多
Emotional °昔
7楼-- · 2019-01-09 09:20

The values in a map may not be unique. But if they are (in your case) you can do as you wrote in your question and create a generic method to convert it:

private static <V, K> Map<V, K> invert(Map<K, V> map) {

    Map<V, K> inv = new HashMap<V, K>();

    for (Entry<K, V> entry : map.entrySet())
        inv.put(entry.getValue(), entry.getKey());

    return inv;
}

Java 8:

public static <V, K> Map<V, K> invert(Map<K, V> map) {
    return map.entrySet()
              .stream()
              .collect(Collectors.toMap(Entry::getValue, Entry::getKey));
}

Example of usage:

public static void main(String[] args) {

    Map<String, Integer> map = new HashMap<String, Integer>();

    map.put("Hello", 0);
    map.put("World!", 1);

    Map<Integer, String> inv = invert(map);

    System.out.println(inv); // outputs something like "{0=Hello, 1=World!}"
}

Side note: the put(.., ..) method will return the the "old" value for a key. If it is not null you may throw a new IllegalArgumentException("Map values must be unique") or something like that.

查看更多
登录 后发表回答