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
}