Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/353.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java8流映射分组操作_Java_Lambda_Java 8_Java Stream - Fatal编程技术网

Java8流映射分组操作

Java8流映射分组操作,java,lambda,java-8,java-stream,Java,Lambda,Java 8,Java Stream,我有以下两门课: 人: 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;

我有以下两门课:

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 + "]";
    }
}
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 + "]";
    }
}
CollectivePerson

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 + "]";
    }
}
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 + "]";
    }
}
其工作和输出如下:

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]]

但我相信有一种更好的方法,分组的流式方法可以达到同样的效果。任何指针都很好。

您可以使用带有合并功能的
收集器。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)
以下是示例输入的输出
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]]}

使用
groupBy
收集器对您的人员进行分组

List<CollectivePerson> list = persons.stream().collect(Collectors.groupingBy(Person::getId)).entrySet().stream().map(x -> {
    // map all the addresses from the list of persons sharing the same id
    Set<String> addresses = x.getValue().stream().map(Person::getAddress).collect(Collectors.toSet());
    // map all the phones from the list of persons sharing the same id
    Set<String> phones = x.getValue().stream().map(Person::getPhone).collect(Collectors.toSet());
    // declare this constructor that takes three parameters
    return new CollectivePerson(x.getKey(), addresses, phones);
}).collect(Collectors.toList());
List List=persons.stream().collect(Collectors.groupingBy(Person::getId)).entrySet().stream().map(x->{
//映射共享相同id的人员列表中的所有地址
Set addresses=x.getValue().stream().map(Person::getAddress).collect(Collectors.toSet());
//从共享相同id的人员列表中映射所有电话
Set phones=x.getValue().stream().map(Person::getPhone).collect(Collectors.toSet());
//声明这个接受三个参数的构造函数
返回新的CollectivePerson(x.getKey()、地址、电话);
}).collect(Collectors.toList());
要使其工作,您需要添加此构造函数:

public CollectivePerson(Long id, Set<String> addresses, Set<String> phones) {
    this.id = id;
    this.addresses = addresses;
    this.phones = phones;
}
public CollectivePerson(长id、设置地址、设置电话){
this.id=id;
this.address=地址;
这个。电话=电话;
}

您应该使用收集器,而不是操作外部
映射。有
toMap
groupingBy
,它们都可以解决这个问题,尽管由于您的类设计有点冗长。主要障碍是缺乏一种现有的方法来将
合并为
集合人
或从给定的
实例构造
集合人
,或合并两个
集合人
实例的方法

使用内置收集器的一种方法是

List<CollectivePerson> collectivePersons = persons.stream()
    .map(p -> {
        CollectivePerson cp = new CollectivePerson(p.getId());
        cp.getAddresses().add(p.getAddress());
        cp.getPhones().add(p.getPhone());
        return cp;
    })
    .collect(Collectors.collectingAndThen(Collectors.toMap(
        CollectivePerson::getId, Function.identity(),
        (cp1, cp2) -> {
            cp1.getAddresses().addAll(cp2.getAddresses());
            cp1.getPhones().addAll(cp2.getPhones());
            return cp1;
        }),
      m -> new ArrayList<>(m.values())
    ));
List collectivePersons=persons.stream()
.map(p->{
CollectivePerson cp=新的CollectivePerson(p.getId());
cp.getAddresses().add(p.getAddress());
cp.getPhone().add(p.getPhone());
返回cp;
})
.collect(收集器.collecting然后(收集器.toMap(
CollectivePerson::getId,Function.identity(),
(cp1,cp2)->{
cp1.getAddresses().addAll(cp2.getAddresses());
cp1.getPhones().addAll(cp2.getPhones());
返回cp1;
}),
m->new ArrayList(m.values())
));
但在这种情况下,自定义收集器可能更简单:

Collection<CollectivePerson> collectivePersons = persons.stream()
    .collect(
        HashMap<Long,CollectivePerson>::new,
        (m,p) -> {
            CollectivePerson cp=m.computeIfAbsent(p.getId(), CollectivePerson::new);
            cp.getAddresses().add(p.getAddress());
            cp.getPhones().add(p.getPhone());
        },
        (m1,m2) -> m2.forEach((l,cp) -> m1.merge(l, cp, (cp1,cp2) -> {
            cp1.getAddresses().addAll(cp2.getAddresses());
            cp1.getPhones().addAll(cp2.getPhones());
            return cp1;
        }))).values();
collectionpersons=persons.stream()
.收集(
HashMap::新建,
(m,p)->{
CollectivePerson cp=m.ComputeFabSent(p.getId(),CollectivePerson::new);
cp.getAddresses().add(p.getAddress());
cp.getPhone().add(p.getPhone());
},
(m1,m2)->m2.forEach((l,cp)->m1.merge(l,cp,(cp1,cp2)->{
cp1.getAddresses().addAll(cp2.getAddresses());
cp1.getPhones().addAll(cp2.getPhones());
返回cp1;
}))).values();
两者都将受益于一个预定义的方法来合并两个
CollectivePerson
实例,而第一个变体也将受益于
CollectivePerson(长id、设置地址、设置电话)
构造函数,或者更好的是,受益于
CollectivePerson(Person p)
构造函数,而第二个构造函数将受益于
CollectivePerson.add(Person p)
方法


请注意,第二个变量返回
映射
s值的
集合
视图,无需复制。如果您确实需要一个
列表
,您可以像使用finisher函数中的第一个变量一样,使用
新的ArrayList(«map».values())
一样简单地压缩它。

无需指定
HashMap::new
;此任务不要求映射是
HashMap
…@Holger的实例,您是对的。出于某种原因,我认为采用合并功能的
toMap
的唯一变体也需要供应商。也就是说,我刚刚注意到3参数toMap(即没有供应商)的实现是
returntomap(keyMapper、valueMapper、mergeFunction、HashMap::new):)是的,在当前的实现中,它总是生成一个
HashMap
,就像
toList()
总是生成一个
ArrayList
,但是,这并不能保证,如果不需要获得这些类型的确切实例,您应该允许实现更改,以获得更改承诺的任何好处。反过来说,如果不需要合并功能,没有任何方法可以选择地图供应商。谢谢你,我已经选择了你的第二个版本,它非常快。在约10秒内对约10000000人进行操作。
Map<Long, CollectivePerson> map = persons.stream().
            collect(Collectors.groupingBy(Person::getId, 
                    Collectors.collectingAndThen(Collectors.toList(),
                            Main::downColl)));
Map<Long, CollectivePerson> map = persons.stream().
            collect(Collectors.groupingBy(Person::getId, 
                    Collectors.collectingAndThen(Collectors.toList(),
                            Main::downColl)));
public static CollectivePerson downColl(List<Person> ps) {

    CollectivePerson cp = new CollectivePerson(ps.get(0).getId());          
    for (Person p:ps) {
        cp.getAddresses().add(p.getAddress());
        cp.getPhones().add(p.getPhone());
    }
    return cp;
}