Java 8流映射分组操作

Tap*_*ose 4 java lambda java-8 java-stream

我有以下两个课程:

Person:

public class Person {

    private final Long id;
    private final String address;
    private final String phone;

    public Person(Long id, String address, String phone) {
        this.id = id;
        this.address = address;
        this.phone = phone;
    }

    public Long getId() {
        return id;
    }

    public String getAddress() {
        return address;
    }

    public String getPhone() {
        return phone;
    }

    @Override
    public String toString() {
        return "Person [id=" + id + ", address=" + address + ", phone=" + phone + "]";
    }
}
Run Code Online (Sandbox Code Playgroud)

CollectivePerson:

import java.util.HashSet;
import java.util.Set;

public class CollectivePerson {

    private final Long id;
    private final Set<String> addresses;
    private final Set<String> phones;

    public CollectivePerson(Long id) {
        this.id = id;
        this.addresses = new HashSet<>();
        this.phones = new HashSet<>();
    }

    public Long getId() {
        return id;
    }

    public Set<String> getAddresses() {
        return addresses;
    }

    public Set<String> getPhones() {
        return phones;
    }

    @Override
    public String toString() {
        return "CollectivePerson [id=" + id + ", addresses=" + addresses + ", phones=" + phones + "]";
    }
}
Run Code Online (Sandbox Code Playgroud)

我想有流操作,以便:

  • Person映射到CollectivePerson
  • addressphonePerson并入addresses,并phones分别CollectivePerson对所有Person具有相同的Sid

我为此目的编写了以下代码:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

public class Main {

    public static void main(String[] args) {
        Person person1 = new Person(1L, "Address 1", "Phone 1");
        Person person2 = new Person(2L, "Address 2", "Phone 2");
        Person person3 = new Person(3L, "Address 3", "Phone 3");
        Person person11 = new Person(1L, "Address 4", "Phone 4");
        Person person21 = new Person(2L, "Address 5", "Phone 5");
        Person person22 = new Person(2L, "Address 6", "Phone 6");

        List<Person> persons = new ArrayList<>();
        persons.add(person1);
        persons.add(person11);
        persons.add(person2);
        persons.add(person21);
        persons.add(person22);
        persons.add(person3);

        Map<Long, CollectivePerson> map = new HashMap<>();
        List<CollectivePerson> collectivePersons = persons.stream()
                .map((Person person) -> {
                    CollectivePerson collectivePerson = map.get(person.getId());

                    if (Objects.isNull(collectivePerson)) {
                        collectivePerson = new CollectivePerson(person.getId());
                        map.put(person.getId(), collectivePerson);

                        collectivePerson.getAddresses().add(person.getAddress());
                        collectivePerson.getPhones().add(person.getPhone());

                        return collectivePerson;
                    } else {
                        collectivePerson.getAddresses().add(person.getAddress());
                        collectivePerson.getPhones().add(person.getPhone());

                        return null;
                    }
                })
                .filter(Objects::nonNull)
                .collect(Collectors.<CollectivePerson>toList());

        collectivePersons.forEach(System.out::println);
    }
}
Run Code Online (Sandbox Code Playgroud)

它的工作和输出如下:

CollectivePerson [id=1, addresses=[Address 1, Address 4], phones=[Phone 1, Phone 4]]
CollectivePerson [id=2, addresses=[Address 2, Address 6, Address 5], phones=[Phone 5, Phone 2, Phone 6]]
CollectivePerson [id=3, addresses=[Address 3], phones=[Phone 3]]
Run Code Online (Sandbox Code Playgroud)

但我相信可能会有一种更好的方式,分组方式实现同​​样的目标.任何指针都会很棒.

Era*_*ran 5

您可以使用Collectors.toMap合并功能:

public static <T, K, U, M extends Map<K, U>>
Collector<T, ?, M> toMap(Function<? super T, ? extends K> keyMapper,
                            Function<? super T, ? extends U> valueMapper,
                            BinaryOperator<U> mergeFunction,
                            Supplier<M> mapSupplier)
Run Code Online (Sandbox Code Playgroud)

映射看起来像这样:

Map<Long,CollectivePerson> collectivePersons =
  persons.stream()
         .collect(Collectors.toMap (Person::getId,
                                    p -> {
                                      CollectivePerson cp = new CollectivePerson (p.getId());
                                      cp.getAddresses().add (p.getAddress());
                                      cp.getPhones().add(p.getPhone());
                                      return cp;
                                    },
                                    (cp1,cp2) -> {
                                      cp1.getAddresses().addAll(cp2.getAddresses());
                                      cp1.getPhones().addAll(cp2.getPhones());
                                      return cp1;
                                    },
                                    HashMap::new));
Run Code Online (Sandbox Code Playgroud)

您可以轻松地提取List<CollectivePerson>Map使用:

new ArrayList<>(collectivePersons.values())
Run Code Online (Sandbox Code Playgroud)

这是Map您的示例输入的输出:

{1=CollectivePerson [id=1, addresses=[Address 1, Address 4], phones=[Phone 1, Phone 4]], 
 2=CollectivePerson [id=2, addresses=[Address 2, Address 6, Address 5], phones=[Phone 5, Phone 2, Phone 6]], 
 3=CollectivePerson [id=3, addresses=[Address 3], phones=[Phone 3]]}
Run Code Online (Sandbox Code Playgroud)