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 TreeSet
s (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.;)