public static void main (String [] args) {
List<AA> list = new ArrayList<AA>();
list.add(new AA("name1", 1));
list.add(new AA("name1", 2));
list.add(new AA("name2", 3));
list.add(new AA("name2", 4));
list.add(new AA("name2", 5));
List<B> listB = list.stream().collect(Collectors.groupingBy(new Function<AA, String>() {
@Override
public String apply(AA aa) {
return aa.getName();
}
}, HashMap::new, Collectors.mapping(new Function<AA, Integer>() {
@Override
public Integer apply(AA aa) {
return aa.getValue();
}
}, Collectors.toList()))).entrySet().stream()
.map(new Function<Map.Entry<String, List<Integer>>, B>() {
@Override
public B apply(Map.Entry<String, List<Integer>> stringListEntry) {
return new B(stringListEntry.getKey(),stringListEntry.getValue());
}
}).collect(Collectors.toList());
System.out.println(JSON.toJSONString(listB));
}
ABvalueInteger
Thank you for the invitation
according to the intuitive needs of the subject, I can give an affirmative answer to List < A >
through groupingBy
of stream
to List < B >
.
of course not.
because only groupingBy
is used, its return, no matter how to use several parameters, can only be a map
, which certainly cannot be transformed into a B
, so it is necessary to use other methods in groupingBy
. For example, after the brothers upstairs use groupingBy
, the generated map
is then looped with entrySet
. If
loops the upstairs brothers
public class B {
private String name;
private List<String> values;
public B(Map.Entry<String, List<String>> entry){
this.name = entry.getKey();
this.values = entry.getValue();
}
}
in that case, the upstairs brother's code can be written like this
List<B> bList = list.stream()
.collect(Collectors.groupingBy(A::getName,
Collectors.mapping(A::getValue, Collectors.toList())))
.entrySet()
.stream()
.map(B::new)
.collect(Collectors.toList());
to put it another way, of course, if the subject wants to finish it at once, he cannot call it done at once. It should be done in a different way, because from the point of view of requirements, the indispensable processing must be a classification operation, as well as a collection operation, but the off-the-shelf classification operation groupingBy
will always return map
. So we can learn the results returned by groupingBy
to construct something similar to the groupingBy
method
because the return result of groupingBy
is a Collector
, it is an interface, so we can customize an implementation class of this interface
this interface, I inadvertently wrote a Collector small note introduced ha. If you are interested, you can take a look at my little understanding of it. For the reason of my time here, I will directly give the implementation class
.
public class BCollector implements Collector<A, List<B>, List<B>> {
@Override
public Supplier<List<B>> supplier() {
return () -> new ArrayList<>();
}
@Override
public BiConsumer<List<B>, A> accumulator() {
// groupingBy
return (bs, a) -> {
Optional<B> optionalB = bs.stream().filter(b -> b.getName().equals(a.getName())).findFirst();
if (optionalB.isPresent()){
B b = optionalB.get();
List<String> values = b.getValues();
if (values == null){
values = new ArrayList<>();
}
values.add(a.getValue());
b.setValues(values);
}else {
B b = new B(a);
bs.add(b);
}
};
}
@Override
public BinaryOperator<List<B>> combiner() {
return (list1, list2) -> {
list1.addAll(list2);
return list1;
};
}
@Override
public Function<List<B>, List<B>> finisher() {
return Function.identity();
}
@Override
public Set<Characteristics> characteristics() {
return Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.IDENTITY_FINISH));
}
}
in addition, B
has added an extra constructor to the class
.
public B(A a){
this.name = a.getName();
this.values = Stream.of(a.getValue()).collect(Collectors.toList());
}
combined with the description of Collector
interface in my previous notes, I believe the subject can simply understand this implementation. With such a collector, the operation will be easier
.
List<B> bList = list.stream().collect(new BCollector());
complete. Emmm, is like this, just for reference, just paste