dezmozz
dezmozz

Reputation: 29

Compare two hashmaps and remove duplicates from second hashmap

HashMap<Double, Date> hm1 = new HashMap<Double, Date>();
HashMap<Double, Date> hm2 = new HashMap<Double, Date>();

hm1.put(11, Wed Feb 23 12:56:24 IST 2022);
hm1.put(12, Wed Feb 23 12:56:48 IST 2022);
hm1.put(13, Wed Feb 23 12:56:45 IST 2022);
hm1.put(14, Wed Feb 23 12:56:51 IST 2022);
hm1.put(15, Wed Feb 23 12:56:50 IST 2022);

hm2.put(11, Wed Feb 23 12:56:24 IST 2022);
hm2.put(12, Wed Feb 23 12:56:48 IST 2022);
hm2.put(13, Wed Feb 23 12:56:45 IST 2022);
hm2.put(17, Wed Feb 23 12:56:37 IST 2022);
hm2.put(18, Wed Feb 23 12:56:28 IST 2022);

Need to compare these two hashmaps and get output as hashmap which contains the filtered entries from hm2 i.e remove duplicates after comparing with hm1

output should be

hm2 = {17=Wed Feb 23 12:56:37 IST 2022,
18=Wed Feb 23 12:56:28 IST 2022}

Upvotes: 0

Views: 1610

Answers (3)

Alexander Ivanchenko
Alexander Ivanchenko

Reputation: 28978

If my understanding is correct you need to remove from the second map all entries that are contained in the first map. I.e. if both a key and its value are the same).

Side note: class Date is obsolete and not encouraged to be used. With Java 8 a new IPA that resides in the package java.time was introduced for such purposes. So I replaced Date with LocalDateTime. If for some reason you can't make this change then simply substitute LocalDateTime with Date.

The first step is to make a defensive copy of the second map. From your definition of the problem the second map itself has to be mutated, so if you don't need to preserve it intact you omit this step, but for future readers, it's worth being included in the code.

To address the problem fluently instead of nested conditions with containsKey() checks you can make use of Java 8 enhancements. The flavor of the remove() that takes a key and value is already mentioned in another answer so I'll sow the alternative approach with the compute() method which was also added into the JDK with Java 8.

Method compute() takes two arguments: a key and remappingFunction which is a BiFunction that excepts as its arguments the given key and existing value associated with that key (it'll be null if the key is absent). If remapping function returns null entry will be removed (in case if it was present).

In the code below iteration happens over the keys in the first map (denoted with a parameter vocub). Method compute() is being applied to the result map, this lambda expression

(k, v) -> !Objects.equals(v, vocab.get(k)) ? v : null

has the following meaning:

  • k - the given key;
  • v - value from result map associated with that key;
  • Objects.equals(v, vocab.get(k)) does a null-friendly comparison of existing value (which could be null) and a value from the first map.

If both values are equal it remaping function yields null, i.e entry will be removed.

public static Map<Double, LocalDateTime> removeDuplicates(Map<Double, LocalDateTime> vocab,
                                                          Map<Double, LocalDateTime> target) {
    Map<Double, LocalDateTime> result = new HashMap<>(target);
    for (Double key: vocab.keySet()) {
        result.compute(key, (k, v) -> !Objects.equals(v, vocab.get(k)) ? v : null);
    }
    return result;
}

If you are comfortable with Stream IPA it could be done by iterating over the entry set of the second map and comparing values in both maps.

public static Map<Double, LocalDateTime> removeDuplicates(Map<Double, LocalDateTime> vocab,
                                                          Map<Double, LocalDateTime> target) {
    return target.entrySet().stream()
            .filter(entry -> !Objects.equals(entry.getValue(), vocab.get(entry.getKey())))
            .collect(Collectors.toMap(Map.Entry::getKey,
                                      Map.Entry::getValue));
}

main()

public static void main(String[] args) {
    Map<Double, LocalDateTime> map1 =
            Map.of(1., LocalDateTime.now().minusDays(3),
                    2., LocalDateTime.now().minusMonths(1),
                    3., LocalDateTime.now().minusDays(5)
                    8., LocalDateTime.now().minusHours(1)); // this key isn't present in the map2

    Map<Double, LocalDateTime> map2 =
            Map.of(1., LocalDateTime.now().minusDays(3),
                    2., LocalDateTime.now().minusMonths(1),
                    3., LocalDateTime.now().minusDays(5),
                    9., LocalDateTime.now());

    System.out.println(removeDuplicates(map1, map2));
}

Output (both versions)

{9.0=2022-02-23T17:56:27.784812600}

Upvotes: 1

Eritrean
Eritrean

Reputation: 16498

Use the remove method which accepts two params (key and value).

Removes the entry for the specified key only if it is currently mapped to the specified value.

So in your case:

hm1.forEach((k,v) -> hm2.remove(k,v));

Upvotes: 2

redPanda
redPanda

Reputation: 86

If key and value must be the same in order to qualify as a duplicate it would be something like:

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

    hm1.put(11, "Wed Feb 23 12:56:24 IST 2022");
    hm1.put(12, "Wed Feb 23 12:56:48 IST 2022");
    hm1.put(13, "Wed Feb 23 12:56:45 IST 2022");
    hm1.put(14, "Wed Feb 23 12:56:51 IST 2022");
    hm1.put(15, "Wed Feb 23 12:56:50 IST 2022");

    hm2.put(11, "Wed Feb 23 12:56:24 IST 2022");
    hm2.put(12, "Wed Feb 23 12:56:48 IST 2022");
    hm2.put(13, "Wed Feb 23 12:56:45 IST 2022");
    hm2.put(17, "Wed Feb 23 12:56:37 IST 2022");
    hm2.put(18, "Wed Feb 23 12:56:28 IST 2022");

    //removing duplicates
    for (Integer key : hm1.keySet()) {
        if (hm2.containsKey(key)) {
            if (hm1.get(key).equals(hm2.get(key))) {
                hm2.remove(key);
            }
        }
    }
    
    // show content of hm2
    System.out.println(hm2);
    

}

If only the key is relevant to qualify as a duplicate use

for (Integer key : hm1.keySet()) {
     hm2.remove(key);           
}

instead of

for (Integer key : hm1.keySet()) {
        if (hm2.containsKey(key)) {
            if (hm1.get(key).equals(hm2.get(key))) {
                hm2.remove(key);
            }
        }
    }

Upvotes: 1

Related Questions