Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Remove duplicate values from HashMap in Java

I have a map with duplicate values:

("A", "1");
("B", "2");
("C", "2");
("D", "3");
("E", "3");

I would like to the map to have

("A", "1");
("B", "2");
("D", "3");

Do you know how to get rid of the duplicate values?

At present, I get 'java.util.ConcurrentModificationException' error.

Thank you.

public static void main(String[] args) {

    HashMap<String, String> map = new HashMap<String, String>();
    map.put("A", "1");
    map.put("B", "2");
    map.put("C", "2");
    map.put("D", "3");
    map.put("E", "3");

    Set<String> keys = map.keySet(); // The set of keys in the map.

    Iterator<String> keyIter = keys.iterator();

    while (keyIter.hasNext()) {
        String key = keyIter.next();
        String value = map.get(key);

        System.out.println(key + "\t" + value);

        String nextValue = map.get(key);

        if (value.equals(nextValue)) {
            map.remove(key);
        }
    }
    System.out.println(map);
}
like image 213
user2610852 Avatar asked Jul 23 '13 14:07

user2610852


3 Answers

Assuming that you use Java 8, it could be done using the Stream API with a Set<String> that will store the existing values:

Map<String, String> map = new HashMap<>();
map.put("A", "1");
...
System.out.printf("Before: %s%n", map);

// Set in which we keep the existing values
Set<String> existing = new HashSet<>();
map = map.entrySet()
    .stream()
    .filter(entry -> existing.add(entry.getValue()))
    .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
System.out.printf("After: %s%n", map);     

Output:

Before: {A=1, B=2, C=2, D=3, E=3}
After: {A=1, B=2, D=3}

NB: Strictly speaking a predicate of a filter is not supposed to be stateful, it should be stateless as mentioned into the javadoc in order to ensure that the result remain deterministic and correct even if we use a parallel stream. However here, I assume that you don't intend to use a parallel stream such that this approach remains valid.

like image 82
Nicolas Filotto Avatar answered Oct 07 '22 21:10

Nicolas Filotto


    Map<String,Object> mapValues = new HashMap<String,Object>(5);
    mapValues.put("1", "TJ");
    mapValues.put("2", "Arun");
    mapValues.put("3", "TJ");
    mapValues.put("4", "Venkat");
    mapValues.put("5", "Arun");

    Collection<Object> list = mapValues.values();
    for(Iterator<Object> itr = list.iterator(); itr.hasNext();)
    {
        if(Collections.frequency(list, itr.next())>1)
        {
            itr.remove();
        }
    }
like image 21
Thananjayan N Avatar answered Oct 07 '22 20:10

Thananjayan N


This can be done using Java 8. The concept of stream is required. The pseudocode, is stream().filter().collect(). If the Initial Map : {A=1, B=2, C=2, D=3, E=3}. Then the required answer after removing the duplicates is {A=1, B=2, D=3} .

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

public class RemoveDuplicates1 {
   public static void main(String[] args) {

        //Initial Map : {A=1, B=2, C=2, D=3, E=3}
        //After =>  {A=1, B=2, D=3} 

      Map<String , String > map = new HashMap<>();
        map.put("A", "1");
        map.put("B", "2");
        map.put("C", "2");
        map.put("D", "3");
        map.put("E", "3");

        System.out.printf("before :   " +map );
        System.out.println("\n");

        Set<String> set = new  HashSet<>();

        map = map.entrySet().stream()
                .filter(entry -> set.add(entry.getValue()))
                .collect(Collectors.toMap(Map.Entry :: getKey ,  Map.Entry :: getValue));
        System.out.printf("after => " + map);

   }
}
like image 42
Soudipta Dutta Avatar answered Oct 07 '22 20:10

Soudipta Dutta