Java Stream 将 JSON 列表聚合到组中
Java Stream to aggregate list of JSONs into groups
我在 java 中有对象列表,像这样。
[
{
"applicationNumber": "100400",
"users": "A",
"category": "student"
},
{
"applicationNumber": "100400",
"users":"B",
"category": "student"
},
{
"applicationNumber": "100400",
"users":"C",
"category": "neighbour"
},
{
"applicationNumber": "100400",
"users": "D",
"category": "neighbour"
},
{
"applicationNumber": "200543",
"users": "C",
"category": "student"
},
{
"applicationNumber": "200543",
"users": "A",
"category": "student"
},
{
"applicationNumber": "200543",
"users":"D",
"category": "friend"
}
]
我想将用户分组为每个应用程序编号的每个类别的列表(顺序无关紧要)。可以参考下面json了解一下。
[
{
"applicationNumber": "100400",
"users": [
"A",
"B"
],
"category": "student"
},
{
"applicationNumber": "100400",
"users": [
"C",
"D"
],
"category": "neighbour"
},
{
"applicationNumber": "200543",
"users": [
"C",
"A"
],
"category": "student"
},
{
"applicationNumber": "200543",
"users": [
"D"
],
"category": "friend"
}
]
我可以使用 for 循环、HashMap 和 if else 条件来做到这一点。我想用 Java 8 stream 来达到同样的效果。谁能帮助我,我是 java.
的新手
PS: 先谢谢你了
我认为在这里使用流有点过度设计,但您可以分两步完成。首先,您需要使用 Collectors.groupingBy()
将您的 pojos 分组到列表映射中。接下来,您需要使用 stream().reduce()
.
将每个列表缩减为单个值
ObjectMapper mapper = new ObjectMapper()
.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
List<Application> applications = Arrays.asList(mapper.readValue(json, Application[].class));
List<Application> groupedApplications = applications.stream()
.collect(Collectors.groupingBy(ApplicationKey::of, Collectors.toList()))
.values().stream()
.map(apps -> apps.stream().reduce(Application::merge))
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList());
Application.java:
public class Application {
private String applicationNumber;
private String category;
private List<String> users = new ArrayList<>();
public static Application merge(Application first, Application second) {
assert ApplicationKey.of(first).equals(ApplicationKey.of(second));
Application merged = new Application(first.applicationNumber, first.category, first.getUsers());
merged.users.addAll(second.getUsers());
return merged;
}
//constructor, getters, setters
}
ApplicationKey.java
public class ApplicationKey {
private String applicationNumber;
private String category;
public static ApplicationKey of(Application application) {
return new ApplicationKey(application.getApplicationNumber(), application.getCategory());
}
public ApplicationKey(String applicationNumber, String category) {
this.applicationNumber = applicationNumber;
this.category = category;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ApplicationKey that = (ApplicationKey) o;
return Objects.equals(applicationNumber, that.applicationNumber) &&
Objects.equals(category, that.category);
}
@Override
public int hashCode() {
return Objects.hash(applicationNumber, category);
}
//getters, setters
}
我在 java 中有对象列表,像这样。
[
{
"applicationNumber": "100400",
"users": "A",
"category": "student"
},
{
"applicationNumber": "100400",
"users":"B",
"category": "student"
},
{
"applicationNumber": "100400",
"users":"C",
"category": "neighbour"
},
{
"applicationNumber": "100400",
"users": "D",
"category": "neighbour"
},
{
"applicationNumber": "200543",
"users": "C",
"category": "student"
},
{
"applicationNumber": "200543",
"users": "A",
"category": "student"
},
{
"applicationNumber": "200543",
"users":"D",
"category": "friend"
}
]
我想将用户分组为每个应用程序编号的每个类别的列表(顺序无关紧要)。可以参考下面json了解一下。
[
{
"applicationNumber": "100400",
"users": [
"A",
"B"
],
"category": "student"
},
{
"applicationNumber": "100400",
"users": [
"C",
"D"
],
"category": "neighbour"
},
{
"applicationNumber": "200543",
"users": [
"C",
"A"
],
"category": "student"
},
{
"applicationNumber": "200543",
"users": [
"D"
],
"category": "friend"
}
]
我可以使用 for 循环、HashMap 和 if else 条件来做到这一点。我想用 Java 8 stream 来达到同样的效果。谁能帮助我,我是 java.
的新手PS: 先谢谢你了
我认为在这里使用流有点过度设计,但您可以分两步完成。首先,您需要使用 Collectors.groupingBy()
将您的 pojos 分组到列表映射中。接下来,您需要使用 stream().reduce()
.
ObjectMapper mapper = new ObjectMapper()
.enable(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY);
List<Application> applications = Arrays.asList(mapper.readValue(json, Application[].class));
List<Application> groupedApplications = applications.stream()
.collect(Collectors.groupingBy(ApplicationKey::of, Collectors.toList()))
.values().stream()
.map(apps -> apps.stream().reduce(Application::merge))
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList());
Application.java:
public class Application {
private String applicationNumber;
private String category;
private List<String> users = new ArrayList<>();
public static Application merge(Application first, Application second) {
assert ApplicationKey.of(first).equals(ApplicationKey.of(second));
Application merged = new Application(first.applicationNumber, first.category, first.getUsers());
merged.users.addAll(second.getUsers());
return merged;
}
//constructor, getters, setters
}
ApplicationKey.java
public class ApplicationKey {
private String applicationNumber;
private String category;
public static ApplicationKey of(Application application) {
return new ApplicationKey(application.getApplicationNumber(), application.getCategory());
}
public ApplicationKey(String applicationNumber, String category) {
this.applicationNumber = applicationNumber;
this.category = category;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ApplicationKey that = (ApplicationKey) o;
return Objects.equals(applicationNumber, that.applicationNumber) &&
Objects.equals(category, that.category);
}
@Override
public int hashCode() {
return Objects.hash(applicationNumber, category);
}
//getters, setters
}