Java-合并给定条件的列表对象 [英] Java - Merge objects of list given a condition
问题描述
我坚信我的问题很简单,但是我无法使用流进行处理(如果有一种方法可以不使用流进行处理,那么它也会有所帮助) 假设我们有此用户列表
I uttlerly convinced that my question its quite simple but im unable to do it with streams (if there is a way to do it without stream will be helpfull too) Suppose that we have this list of users
public class Users {
String firstName;
String lastName;
double accountBalance;
String type;
String extraField;
}
,并假设我们的列表中有以下数据<用户>
and suppose that we have the following data in my List < Users >
"Users": [{
"firstName": "Scott",
"lastName": "Salisbury",
"accountBalance": "100",
"type" : "A"
}, {
"firstName": "John",
"lastName": "Richards",
"accountBalance": "200",
"type" :"C"
}, {
"firstName": "John",
"lastName": "Richards",
"accountBalance": "200",
"type " : "C",
"ExtraField": "Apply"
}]
给定firstName,lastName和type在列表中出现两次的预期结果,只需合并常见结果而不遗漏任何字段
预期产量
the expected result here its given that firstName, lastName and type appears twice on the list just merge the results that are common without missing any field
Expected output
"Users": [{
"firstName": "Scott",
"lastName": "Salisbury",
"accountBalance": "100",
"type" : "A"
}, {
"firstName": "John",
"lastName": "Richards",
"accountBalance": "400",//merged values
"type " : "C",
"ExtraField": "Apply" //value that remains in one object of the list
}]
推荐答案
您可以创建一个包含三个字段的键类,例如
You can create a key class containing the three fields, like
@Data
class UserKey {
String firstName;
String lastName;
String type;
static UserKey from(User user) { /* TODO (trivial) */ }
}
分组
可以用来对用户进行分组
Those can be used to group your users
Map<UserKey,List<User>> grouped =
users.stream().collect(Collectors.groupingBy(UserKey::from));
然后,这些列表中的每一个都可以通过合并
Each of these lists can then be merged by
Optional<User> summed = userList.stream()
.collect(Collectors.reducing((u1, u2) -> {
u1.setAccountBalance(u1.accountBalance() + u2.accountBalance());
});
这也可以直接作为groupingBy
的下游收集器提供:
This can also be given directly as a downstream collector to the groupingBy
:
Map<UserKey,Optional<User>> mergedMap =
users.stream().collect(Collectors.groupingBy(UserKey::from,
Collectors.reducing((u1, u2) -> {
u1.setAccountBalance(u1.accountBalance() + u2.accountBalance());
return u1;
}));
由于保证可以填充这些Optional
,因此您可以在其上调用get()
;而且,您不再需要按键,所以
Since those Optional
s are guaranteed to be filled, you can just call get()
on them; also, you don't need the keys anymore, so
List<User> result = mergedMap.values().stream()
.map(Optional::get)
.collect(toList());
toMap
正如Naman在评论中所建议的那样,您也可以通过toMap
对此进行快捷操作.
As Naman suggested in the comments, you can also shortcut this by toMap
.
Map<UserKey,User> mergedMap = users.stream()
.collect(toMap(UserKey::from, Function.identity(),
(u1, u2) -> {
u1.setAccountBalance(u1.accountBalance() + u2.accountBalance());
return u1;
}));
List<User> result = new ArrayList<>(mergedMap.values());
请注意,reduce函数具有操作列表中原始用户对象之一的副作用,因此请确保您不再需要它们.
Note that the reducing function has the side effect of manipulating one of the original user objects in the list, so make sure you don't need them again.
这篇关于Java-合并给定条件的列表对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!