首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java 8流合并部分复制

Java 8流合并部分复制
EN

Stack Overflow用户
提问于 2018-01-24 02:09:53
回答 3查看 4.2K关注 0票数 4

我有一个像这样的POJO:

代码语言:javascript
复制
public class Account {
    private Integer accountId;
    private List<String> contacts;
}

equals和hashCode方法被设置为使用accountId字段来标识唯一性,因此任何具有相同accountId的帐户都是相等的,而不管contacts包含什么。

我有一个帐户列表,有一些重复与相同的accountId。如何使用Java8StreamAPI将这些副本合并在一起?

例如,帐户列表包含:

代码语言:javascript
复制
+-----------+----------+
| accountId | contacts |
+-----------+----------+
|         1 | {"John"} |
|         1 | {"Fred"} |
|         2 | {"Mary"} |
+-----------+----------+

我希望它能提供这样的账户清单:

代码语言:javascript
复制
+-----------+------------------+
| accountId |     contacts     |
+-----------+------------------+
|         1 | {"John", "Fred"} |
|         2 | {"Mary"}         |
+-----------+------------------+
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-01-24 02:46:53

使用Collectors.toMap参考文献:https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html#toMap-java.util.function.Function-java.util.function.Function-java.util.function.BinaryOperator-

代码语言:javascript
复制
@lombok.Value
class Account {
    Integer accountId;
    List<String> contacts;
}

List<Account> accounts = new ArrayList<>();
//Fill
List<Account> result = new ArrayList<>(accounts.stream()
    .collect(
        Collectors.toMap(Account::getAccountId, Function.identity(), (Account account1, Account account2) -> {
            account1.getContacts().addAll(account2.getContacts());
            account2.getContacts().clear();
            return account1;
        })
    )
    .values());
票数 4
EN

Stack Overflow用户

发布于 2018-01-24 11:26:57

干净的Stream解决方案可以是安静的、复杂的,所以您最好使用一个集合API解决方案,该解决方案需要遵守的约束较少。

代码语言:javascript
复制
HashMap<Integer, Account> tmp = new HashMap<>();
listOfAccounts.removeIf(a -> a != tmp.merge(a.getAccountId(), a, (o,n) -> {
    o.getContacts().addAll(n.getContacts());
    return o;
}));

在将它们的联系人添加到该id的第一个帐户后,这将直接从列表中删除所有具有重复id的元素。

当然,这假设列表支持删除,getContacts()返回的列表是对存储列表的引用,并支持添加元素。

解决方案是围绕Map.merge构建的,如果键不存在,它将添加指定的对象;如果键已经存在,则计算合并函数。合并函数在添加联系人之后返回旧对象,因此我们可以进行引用比较(a != …)来确定应该删除的副本。

票数 2
EN

Stack Overflow用户

发布于 2018-01-24 04:01:14

您可以将两个构造函数和一个merge方法添加到将组合联系人的Account类中:

代码语言:javascript
复制
public class Account {

    private final Integer accountId;

    private List<String> contacts = new ArrayList<>();

    public Account(Integer accountId) {
        this.accountId = accountId;
    }

    // Copy constructor
    public Account(Account another) {
        this.accountId = another.accountId;
        this.contacts = new ArrayList<>(another.contacts);
    }

    public Account merge(Account another) {
        this.contacts.addAll(another.contacts);
        return this;
    }

    // TODO getters and setters
}

那么,你有几个选择。一种是使用Collectors.toMap将帐户收集到地图上,按accountId进行分组,并通过Account.merge方法将帐户的联系人与相等的accountId合并。最后,获取映射的值:

代码语言:javascript
复制
Collection<Account> result = accounts.stream()
    .collect(Collectors.toMap(
        Account::getAccountId, // group by accountId (keys)
        Account::new,          // use copy constructor (values)
        Account::merge))       // merge values with equal key
    .values();

您需要对值使用复制构造函数,否则在调用Account.merge时会更改原始列表的帐户。

一种类似的方法(没有流)是使用Map.merge方法:

代码语言:javascript
复制
Map<Integer, Account> map = new HashMap<>();
accounts.forEach(a -> 
    map.merge(a.getAccountId(), new Account(a), Account::merge));
Collection<Account> result = map.values();

同样,您需要使用复制构造函数来避免原始列表帐户上的不需要的突变。

第三个更优化的选项(因为它没有为列表中的每个元素创建一个新帐户)包括使用Map.computeIfAbsent方法:

代码语言:javascript
复制
Map<Integer, Account> map = new HashMap<>();
accounts.forEach(a -> map.computeIfAbsent(
        a.getAccountId(), // group by accountId (keys)
        Account::new)     // invoke new Account(accountId) if absent
    .merge(a));           // merge account's contacts
Collection<Account> result = map.values();

上面的所有选项都返回一个Collection<Account>。如果您需要一个List<Account>,您可以这样做:

代码语言:javascript
复制
List<Account> list = new ArrayList<>(result);
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48413789

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档