Home > Net >  @Override TreeSet add methode for add juste 4 elements (on Java)
@Override TreeSet add methode for add juste 4 elements (on Java)

Time:12-06

I have a List, i stream it to an Treemap with key and values where the values are a TreeSet and for this TreeSet I what juste add 4 first elements to the Treeset stream not all element

Map<Integer, Set<Person>> stream_exo = ListOfPerson.stream()
                .collect(
                        Collectors.groupingBy(
                                p -> p.getYear(), 
                                TreeMap::new, Collectors.toCollection(TreeSet2::New)));

here is the treeSet Class of java :

public class TreeSet<E> extends AbstractSet<E>
                   implements NavigableSet<E>, Cloneable, java.io.Serializable {

    private static final Object PRESENT = new Object();
    
    private transient TreeMap<E,Object> internalMap;
    
    public boolean add(E e) {
        return this.internalMap.put(e, PRESENT)==null;
    }
}

I want to costume function (add) for TreeSet to add just 4 elements to the TreeSet, someone can ask me how we can do that ?

CodePudding user response:

this has nothing to do with streams...just plain inheritance.

create a new class "MaxFourTreeSet" which "extends TreeSet" and override the add() function to add your condition. then, in your stream use MaxFourTreeSet::new instead of TreeSet::new. that's all.

public class MaxFourTreeSet<E> extends TreeSet<E> {

@Override
public boolean add(E e) {
    if (this.size() <= 4) {
        return super.add(e);
    } 
    return false;
 } 
}

(code not accurate)

CodePudding user response:

First

To Use a TreeSet ("ordered set"), the values (<V>) must implement Comparable<V> or we have to provide a Comparator<Person> at TreeSet construction.

Second

Check this (if we got the problem right):

package com.example;

import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.toSet;

import java.util.List;
import java.util.Map;
import java.util.Set;

public class Test {
    public static void main(String[] args) {
        // test data:
        List<Person> list = List.of(new Person(1969), new Person(1969), new Person(1969), new Person(1969),
            new Person(1969), // 5
            new Person(1971), new Person(1971), new Person(1971), new Person(1971),
            new Person(1971), // 5
            new Person(1999), new Person(1999) // 2
        );
        // action:
        Map<Integer, Set<Person>> stream_exo = list.stream()
            .collect( //..as we had
                groupingBy( // ...
                    p -> p.year, // ... key - function
                    collectingAndThen( // value - "downstream"
                        toSet(), // collector - function (downstream)
                        s ->  s // (and then) set - (finalizer) fuction
                            .stream() //  stream once more ;(, unfortunately i found no nicer way
                            .limit(4) // limit to 4, and finally:
                            .collect(  // ...collect
                                toSet()  // to set TreeSet::new, when Person is Comparable<Person>
                            )
                    ) // end-collectingAndThen
                ) // end-groupingBy
            ); // end-collect
        // output verification:
        stream_exo.forEach((k, v) -> {
            System.out.format("%s:\t%d%n", "key", k);
            v.forEach(p -> System.out.println(p));
        });

    }
}

class Person {
    final int year;

    Person(int pYear) {
        year = pYear;
    }
}

Output:

key:    1969
com.example.Person@31befd9f
com.example.Person@1c20c684
com.example.Person@2f2c9b19
com.example.Person@13221655
key:    1971
com.example.Person@3e3abc88
com.example.Person@1218025c
com.example.Person@548c4f57
com.example.Person@816f27d
key:    1999
com.example.Person@53d8d10a
com.example.Person@6ce253f1

So collectingAndThen (to stream() once more, to limit(), and collect() again) is my answer for that particular requirement!


Third

If we want to use a TreeSet, we have to implement the mentioned (First) interface, "...and finally":

collect(toSet(TreeSet::new)))));

Finally

To make it really a TreeMap:

TreeMap<Integer, Set<Person>> stream_exo = list.stream()
   ....

we need to:

...
groupingBy(
    p -> p.year, 
    TreeMap::new, // do additonally this!
    collectingAndThen( ...

To have also nested TreeSets (without modifying Person, basing on person.year), this is it:

TreeMap<Integer, Set<Person>> stream_exo = list // TreeMap result (Integer IS Comparable<Integer>;)
    .stream()
    .collect(
        groupingBy(
            p -> p.year,
            TreeMap::new,
            collectingAndThen(
                toSet(), // if we want the "intermediary" set also as TreeSet(ordered!), then here!
                s -> 
                    s.stream()
                    .limit(4)
                    .collect(
                        toCollection(() -> {  // TreeSet leafs:
                            return new TreeSet<> ( // with inline comparator
                                (p1, p2) -> Integer.compare(p1.year, p2.year));
                        }
                    )
            )
        )
    );   

...but Comparable<Person> by the year is useless here, since year already grouped/unique.;)

  • Related