Jany Gwan
Jany Gwan

Reputation: 77

Find the different values in 2 HashMaps

I have 2 HashMaps with millions of records. For simplicity, I will deal with only few records. I want to find the values which are in map a that are not in map b. Is there a function to do this? What's the quickest way to go about it?

Map a = new HashMap();
a.put(1, "big");
a.put(2, "hello");
a.put(3, "world");

Map b = new HashMap();

b.put(1,"hello");
b.put(2, "world");

In this case, output should be "big" since it is in a and not in b.

Upvotes: 4

Views: 1067

Answers (6)

Saketh Kotha
Saketh Kotha

Reputation: 101

I am assuming that the unique values u want does not depend on the key position (2, "hello" and 1,"hello")

A single line of code should do it.

a.values().removeAll(b.values());

caution: this removes all the repeating values from 'a' hashmap

Upvotes: 0

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726559

Here is a fast, non-destructive, solution based on streams:

Map<Integer, String> a = ...;
Map<Integer, String> b = ...;
Set<String> bVal = new HashSet<String>(b.values());
String[] res = a.values()
    .stream()
    .filter(s -> bVal.contains(s))
    .toArray(String[]::new);

res contains all values present in both maps. Upon completion of this code both maps remain in their original state.

The code requires additional memory of the size proportional to the size of the second map. If one of your maps is significantly smaller than the other, you could save space by using the smaller map as map b in the example above.

Demo.

Upvotes: 1

Tunaki
Tunaki

Reputation: 137084

You are looking for the removeAll operation on the values of the map.

public static void main(String[] args) {
    Map<Integer, String> a = new HashMap<>();
    a.put(1, "big");
    a.put(2, "hello");
    a.put(3, "world");

    Map<Integer, String> b = new HashMap<>();
    b.put(1,"hello");
    b.put(2, "world");

    a.values().removeAll(b.values()); // removes all the entries of a that are in b

    System.out.println(a); // prints "{1=big}"
}

values() returns a view of the values contained in this map:

Returns a Collection view of the values contained in this map. The collection is backed by the map, so changes to the map are reflected in the collection, and vice-versa.

So removing elements from the values effectively removes the entries. This is also documented:

The collection supports element removal, which removes the corresponding mapping from the map, via the Iterator.remove, Collection.remove, removeAll, retainAll and clear operations.


This removes from the map in-place. If you want to have a new map with the result, you should call that method on a new map instance.

Map<Integer, String> newMap = new HashMap<>(a);
newMap.values().removeAll(b.values());

Side-note: don't use raw types!

Upvotes: 10

david
david

Reputation: 1016

If you're allowed to use Apache Commons Collections 4, you can use SetUtils.difference(), which probably has similar performance to @Tunaki's answer.

Upvotes: 2

ParkerHalo
ParkerHalo

Reputation: 4430

The solution of @Tunaki will work fine, is readable and short.

Just for the sake of completeness the solution "by hand":

for (String s : a.values()) {
    if (!b.containsValue(s)) {
        System.out.println (s);
        // process the value (e.g. add it to a list for further processing)
    }
}

Upvotes: 2

osanger
osanger

Reputation: 2352

A.containsValue(value) && !B.containsValue(value)

See: https://docs.oracle.com/javase/7/docs/api/java/util/HashMap.html#containsValue(java.lang.Object)

Upvotes: 0

Related Questions