Apply Distinct Function on TreeMap
Asked Answered
B

3

1

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]
Behring answered 18/9, 2014 at 6:15 Comment(12)
Why is it 3= [3, 33]? What happened to 4? Which key should remain for 2?Gilmour
this is expected result. as you see 2 and 3 have the same value which is 2. Is it even possible to have my expected result?Behring
No, your expected result doesn't make much sense considering you want the key and value of an entry. [3, 33] should be mapped to 4. You'll have to define how the mapping should behave.Gilmour
so what do you mean by define how the mapping should behave?Behring
Currently, your request of how I can printout the key and value at the same time without having duplicate value doesn't really match your expected results. Give us something that does.Gilmour
@SotiriosDelimanolis I think I just need a counter that is all, but I do not know how to inject it to my code.Behring
I don't understand anymore. You don't seem to know what you're asking...Gilmour
Let us continue this discussion in chat.Behring
I deleted my answer, as I cannot continue working on this. Unfortunately you have to keep a second collection for checking duplicates.Dolora
@Dolora why I was looking to see your answerBehring
possible duplicate of Java 8 Distinct by propertyHoicks
@StuartMarks was it on tree map?Behring
B
0
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]
Bairam answered 18/9, 2014 at 7:31 Comment(7)
so no there is no duplicate value? can you plz post up the outcome of this code?Behring
I am not near a compiler, but it should print 1=[1] 2=[2] 4=[3, 33]Bairam
@KickButtowski In your setup, you have test.get(4).add("3, 33");, so it will print 4=[3,33].Bairam
is not possible that key become 3 not 4? plz explain ur approaches so I can accept itBehring
@KickButtowski Can you clarify where you expect 3 to come from? In the original TreeMap, the set ["3,33"] is associated with key 4.Bairam
I thought when u get rid of duplicate values keys are shrunk too cuz 2 and 3 have same value. what's is going to happen key three in ur approaches?Behring
@KickButtowski I added an edit. See if that helps you.Bairam
K
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.

Kranz answered 18/9, 2014 at 9:26 Comment(0)
A
0
   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);
      }
    });
Asphaltite answered 18/9, 2014 at 6:17 Comment(5)
I want to apply lambdaBehring
Sorry I just realised I misunderstood your problem.Asphaltite
You just need to keep track of the set of values you've processed so far - see edited answerAsphaltite
I totally appreciate your answer and I will take a look at it later, but my question is how I can use Java 8 to accomplish thatBehring
I don't think in this case you're gaining anything by using lambdas. Instead of the for-loop it would just be test.entrySet().stream().forEach(entry -> everything else is the sameAsphaltite
B
0
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]
Bairam answered 18/9, 2014 at 7:31 Comment(7)
so no there is no duplicate value? can you plz post up the outcome of this code?Behring
I am not near a compiler, but it should print 1=[1] 2=[2] 4=[3, 33]Bairam
@KickButtowski In your setup, you have test.get(4).add("3, 33");, so it will print 4=[3,33].Bairam
is not possible that key become 3 not 4? plz explain ur approaches so I can accept itBehring
@KickButtowski Can you clarify where you expect 3 to come from? In the original TreeMap, the set ["3,33"] is associated with key 4.Bairam
I thought when u get rid of duplicate values keys are shrunk too cuz 2 and 3 have same value. what's is going to happen key three in ur approaches?Behring
@KickButtowski I added an edit. See if that helps you.Bairam

© 2022 - 2024 — McMap. All rights reserved.