Search code examples
javalambdadistinctjava-8treemap

Apply Distinct Function on TreeMap


Code:

   Map<Integer, HashSet<String>> test = new TreeMap<>();
    test.put(1, new HashSet<>());
    test.put(2, new HashSet<>());
    test.put(3, new HashSet<>());
    test.put(4, new HashSet<>());

    test.get(1).add("1");
    test.get(2).add("2");
    test.get(3).add("2");
    test.get(4).add("3, 33");

    //get value of treemap and get rid of the duplicate by using distinct and printout 
    //at the end
    test.values().stream().distinct().forEach(i -> System.out.println(i));

output:

[1]
[2]
[3, 33]

My question is how I can printout the key and value at the same time without having duplicate value?

Expected Result:

  1= [1]
  2= [2]
  3= [3, 33]

I even try below code, yet it gives me the treemap with the duplicate values:

Code:

   List<Map.Entry<Integer, HashSet<String>>> list = new ArrayList<>();
   list.addAll(test.entrySet());
   list.stream().distinct().forEach( i -> System.out.println(i));

Output:

1=[1]
2=[2]
3=[2]
4=[3, 33]

Solution

  • test.entrySet().stream()
            .collect(
                    Collectors.toMap(
                            Map.Entry::getValue,
                            x -> x,
                            (a, b) -> a
                    )
            ).values()
            .forEach(System.out::println);
    

    Edit:

    Explanation: this snippet will take the stream of entries and put them into a map of value to entry while discarding duplicates (see javadoc for Collectors#toMap). It then takes the values of that map as a collection. The result is the collection of map entries that are distinct by Map.Entry::getValue.

    Edit 2:

    From your comments I think I understand what you are trying to do. You are using this TreeSet as a 1-based list and you want keys to collapse as you remove duplicate values. Is that correct? Maybe you can explain why you are doing this instead of just using a list.

    Streams aren't well-suited for this sort of approach, so this will not be pretty, but here you go: Stream the values, eliminate duplicates, collect into a list, then turn the list back into a map.

    test.values().stream()
            .distinct()
            .collect(
                    Collectors.collectingAndThen(
                            Collectors.toList(),
                            lst -> IntStream.range(0, lst.size()).boxed().collect(
                                    Collectors.toMap(i -> i + 1, i -> lst.get(i))
                            )
                    )
            ).entrySet().forEach(System.out::println);
    
    output:
     1=[1]
     2=[2]
     3=[3, 33]