Java 8个收集器groupBy并分成一个单独的class

Java 8 collectors groupBy and into a separate class

我有一个 Persons 的列表,其中有一些重名。

class Person {
  String name;
}

我想将其转换为 GroupedPersons 的列表,其中包含通用名称和所有具有该名称的人的列表。

class GroupedPerson {
  String name;
  List<A> as;
}

是否可以使用一个收集器来完成此操作,而无需任何中间映射或额外的 类?

我想一种方法是:

 persons
   .stream()          
   .collect(Collectors.collectingAndThen(Collectors.groupingBy(
           Person::getName),
           map -> {
               return map.entrySet()
                         .stream()
                         .map(en -> new GroupedPerson(en.getKey(), en.getValue()))
                         .collect(Collectors.toList());
}));

或者,您可以使用 toMap:

persons  
   .stream()
   .collect(Collectors.toMap(
            Person::getName,
            x -> {
                  List<Person> l = new ArrayList<>();
                  l.add(x);
                  return new GroupedPerson(x.getName(), l);
            },
            (left, right) -> {
                 left.getAs().addAll(right.getAs());
                 return left;
            }))
   .values();

是的,你可以做到。这是一种方法:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class GroupedStream {

    public static void main(String[] args) {
        List<GroupedPerson> groupedPersons = Arrays.asList("john harry john harry sam jordon bill steve bill".split(" "))
            .stream()
            .map(name -> new Person(name))
            .map(person -> new Object[] {person.name, new ArrayList<>()})
            .collect(Collectors.toMap(tuple-> (String) tuple[0], tuple -> (List<Person>) tuple[1] ))
            .entrySet()
            .stream()
            .map(entry -> new GroupedPerson(entry.getKey(), entry.getValue()))
            .collect(Collectors.toList());
    }

    static class Person {
        public final String name;

        public Person(String name) {
            super();
            this.name = name;
        }

    }

    static class GroupedPerson {

        public final String name;
        public final List<Person> person;

        public GroupedPerson(String name, List<Person> person) {
            this.name = name;
            this.person = person;
        }

    }

}

如果您将 GroupedPerson 模型修改为以下内容:

public class GroupedPerson {
    private String name;
    private List<Person> people;

    public GroupedPerson(String name) {
        this.name = name;
        people = new ArrayList<>();
    }

    public void addPeople(List<Person> people) {
        this.people.addAll(people);
    }

    public void addPerson(Person person){
           people.add(person);
    }

    public List<Person> getPeople(){
        return Collections.unmodifiableList(people);
    }

    public String getName() {
        return name;
    }    
}

然后你可以有一个 CollectionGroupedPerson 个对象,其中包含名称和所有具有该特定名称的相应人员,如下所示:

Collection<GroupedPerson> resultSet = peopleList
                .stream()
                .collect(Collectors.toMap(Person::getName,
                        p -> {
                            GroupedPerson groupedPerson = new GroupedPerson(p.getName());
                            groupedPerson.addPerson(p);
                            return groupedPerson;
                        },
                        (p, p1) -> {
                            p.addPeople(p1.getPeople());
                            return p;
                        }
                )).values();

如果出于某种原因您不希望接收器类型为 Collection<T> 那么您可以转换为特定的集合类型(如果认为合适的话,只需简单地执行即可)。

List<GroupedPerson> result = new ArrayList<>(resultSet);