Apply Distinct Function on TreeMap

2019-07-28 23:54发布

问题:

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]

回答1:

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]


回答2:

Your question is a bit confusion as you say you want the key for distinct values but duplicate values obviously have duplicate keys. It’s not clear why you expect the key 2 for the value 2 in your example as the value 2 is present two times in the source map, having the keys 2 and 3.

The following code will gather all keys for duplicates:

test.entrySet().stream().collect(Collectors.groupingBy(
     Map.Entry::getValue, Collectors.mapping(Map.Entry::getKey, Collectors.toList())))
  .forEach((value,keys) -> System.out.println(keys+"\t= "+value));

It will print:

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

for your example map. It’s up to you to pick up the key 2 from the key list [2, 3] if you have a rule for the selection.



回答3:

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

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

    int count = 0;
    HashSet<String> distinctValues = new HashSet<>();
    test.entrySet().stream().forEach(entry -> {
      HashSet<String> entryValues = new HashSet<>();
      entryValues.addAll(entry.getValue());
      // ignore any values you've already processed
      entryValues.removeAll(distinctValues);
      if (!entryValues.isEmpty()) {
          System.out.println(++count + " = " + entryValues);
          distinctValues.addAll(entryValues);
      }
    });