Java 8 Java 8流合并部分重复项
我有一个POJO,看起来像这样: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"} | |
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;
}));