Java 8 Java 8流合并部分重复项

Java 8 Java 8流合并部分重复项,java-8,java-stream,Java 8,Java Stream,我有一个POJO,看起来像这样: public class Account { private Integer accountId; private List<String> contacts; } +-----------+------------------+ | accountId | contacts | +-----------+------------------+ | 1 | {"John", "Fred"} | |

我有一个POJO,看起来像这样:

public class Account {
    private Integer accountId;
    private List<String> contacts;
}
+-----------+------------------+
| accountId |     contacts     |
+-----------+------------------+
|         1 | {"John", "Fred"} |
|         2 | {"Mary"}         |
+-----------+------------------+
我希望它能产生一个类似这样的账户列表:

public class Account {
    private Integer accountId;
    private List<String> contacts;
}
+-----------+------------------+
| accountId |     contacts     |
+-----------+------------------+
|         1 | {"John", "Fred"} |
|         2 | {"Mary"}         |
+-----------+------------------+

使用收集器。toMapRef:

@lombok.Value
类别帐户{
整数accountId;
列出联系人名单;
}
列表帐户=新的ArrayList();
//填满
列表结果=新建ArrayList(accounts.stream()
.收集(
Collectors.toMap(Account::getAccountId,Function.identity(),(Account account1,Account account2)->{
account1.getContacts().addAll(account2.getContacts());
account2.getContacts().clear();
返回帐户1;
})
)
.values());

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

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
}
您需要对值使用复制构造函数,否则在调用
Account.merge
时,您将改变原始列表的帐户

一种等效方法(无流)是使用以下方法:

以上所有选项都返回一个
集合
。如果您需要一个
列表
,您可以执行以下操作:

List<Account> list = new ArrayList<>(result);
List List=newarraylist(结果);

一个干净的流API解决方案可能非常复杂,因此您最好使用一个约束较少的集合API解决方案

HashMap<Integer, Account> tmp = new HashMap<>();
listOfAccounts.removeIf(a -> a != tmp.merge(a.getAccountId(), a, (o,n) -> {
    o.getContacts().addAll(n.getContacts());
    return o;
}));
HashMap tmp=newhashmap();
listOfAccounts.removeIf(a->a!=tmp.merge(a.getAccountId(),a,(o,n)->{
o、 getContacts().addAll(n.getContacts());
返回o;
}));
在将联系人添加到id的第一个帐户后,这将直接从列表中删除具有重复id的所有元素

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


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

@Holger我已编辑了我的答案。我已经删除了自定义收集器示例,因为没有干净简单的方法来创建带有
accountId
Account
帐户,而不在
merge
方法或新的专用
acculate
方法中设置属性。再次感谢您的反馈。我接受了这个答案,因为它使用的是流API,我不需要修改POJO。
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();
List<Account> list = new ArrayList<>(result);
HashMap<Integer, Account> tmp = new HashMap<>();
listOfAccounts.removeIf(a -> a != tmp.merge(a.getAccountId(), a, (o,n) -> {
    o.getContacts().addAll(n.getContacts());
    return o;
}));