简体   繁体   English

如何对 jsonObject 的值求和并在 JAVA 中的 jsonArray 中创建 sum 的新 jsonobject?

[英]How to sum values of jsonObject and create new jsonobject of sum inside a jsonArray in JAVA?

I have JSON Array as below and want to sum values of JSON object and create new JSON object of sum inside a JSON array:我有如下的 JSON 数组,想对 JSON 对象的值求和并在 JSON 数组中创建新的 JSON 对象:

{
   "client":[
      {
         "member":12,
         "group":"g1"
      },
      {
         "member":17,
         "group":"g2"
      }
   ],
   "client2":[
      {
         "member":14,
         "group":"g11"
      },
      {
         "member":175,
         "group":"g22"
      }
   ]
}

I want to sum the member value for each jsonobject inside the jsonarray and create extra json and put it inside client array.我想对 jsonarray 中每个 jsonobject 的成员值求和并创建额外的 json 并将其放入客户端数组中。 The expected json should look like below:预期的 json 应如下所示:

{
   "client":[
      {
         "member":12,
         "group":"g1"
      },
      {
         "member":17,
         "group":"g2"
      },
      {
         "totalMember":29,
         "group":"all"
      }
   ],
   "client2":[
      {
         "member":14,
         "group":"g11"
      },
      {
         "member":175,
         "group":"g22"
      },
      {
         "totalMember":189,
         "group":"all"
      }
   ]
}

I tried as:我试过:

    mainJson.fieldNames().forEach(fn->{
      JsonArray jsonArray  = mainJson.getJsonArray(fn);
      int id = 0;
      for (int i = 0; i < jsonArray.size(); i++) {
          id += jsonArray.getJsonObject(i).getInteger("id");
        JsonObject jsonObject = new JsonObject().put("id",id).put("group","all");
        jsonArray.add(jsonObject);
        mainJson.put(fn,jsonArray);
      }
    });

So, below is a full worked example using gson library (googles json parser).因此,下面是一个使用gson库( googles json 解析器)的完整示例。

First i created the class for defining the initial json file:首先,我创建了用于定义初始 json 文件的类:

import java.io.Serializable;
import java.util.ArrayList;

public class ClientSer implements Serializable {
    ArrayList<ClientDataSer> client;
    ArrayList<ClientDataSer> client2;

    public ClientSer(ArrayList<ClientDataSer> client, ArrayList<ClientDataSer> client2) {
        this.client = client;
        this.client2 = client2;
    }

    public ArrayList<ClientDataSer> getClient() {
        return client;
    }

    public void setClient(ArrayList<ClientDataSer> client) {
        this.client = client;
    }

    public ArrayList<ClientDataSer> getClient2() {
        return client2;
    }

    public void setClient2(ArrayList<ClientDataSer> client2) {
        this.client2 = client2;
    }
}

With client data ser looking like:客户端数据服务器看起来像:

public class ClientDataSer extends ClientDataParentSer {
    int member;

    public ClientDataSer(int member, String group) {
        super(group);
        this.member = member;
    }

    public int getMember() {
        return member;
    }

    public void setMember(int member) {
        this.member = member;
    }

}

In order for gson to uses files as definitions of data structure, they need to be serialisable.为了让 gson 使用文件作为数据结构的定义,它们需要是可序列化的。 I will get the why ClientDataSer extends ClientDataParentSer in a moment.我马上就会明白为什么 ClientDataSer 会扩展 ClientDataParentSer。

The code for reading this file, caluclating the total member value and printing it to another file is shown below:读取该文件、计算成员总数并将其打印到另一个文件的代码如下所示:

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import java.io.*;
import java.util.ArrayList;

public class Main {

    public static void main(String[] args) {


        Gson gson = new GsonBuilder()
                .setPrettyPrinting()
                .create();

        try (Reader reader = new FileReader("test.json")) {

            // Convert JSON File to Java Object
            ClientSer clientSer = gson.fromJson(reader, ClientSer.class);

            ClientNewSer clientNewSer = new ClientNewSer(getNewClientData(clientSer.getClient()), getNewClientData(clientSer.getClient2()));

            try {
                Writer writer = new FileWriter("testNew.json");
                gson.toJson(clientNewSer, writer);
                writer.flush();
                writer.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private static ArrayList<ClientDataParentSer> getNewClientData(ArrayList<ClientDataSer> clientDataSerList) {

        ArrayList<ClientDataParentSer> clientDataSers = new ArrayList<>();

        int memberCounter = 0;
        for (ClientDataParentSer clientDataSer : clientDataSerList) {

            clientDataSers.add(clientDataSer);

            memberCounter += ((ClientDataSer)clientDataSer).getMember();
        }

        ClientDataNewSer clientDataNewSer = new ClientDataNewSer("all", memberCounter);

        clientDataSers.add(clientDataNewSer);

        return clientDataSers;

    }
}

So, as you wanted client and client2 to contain a list each with 2 different obejects (one with field member and group, and the other with fields total member and group), we had to do some hierarchy stuff.因此,由于您希望 client 和 client2 包含一个列表,每个列表具有 2 个不同的对象(一个具有成员和组字段,另一个具有成员和组字段),我们必须做一些层次结构的事情。

If we make a parent class containing the common field (group):如果我们创建一个包含公共字段(组)的父类:

import java.io.Serializable;

public class ClientDataParentSer implements Serializable {


    private final String group;

    public ClientDataParentSer(String group) {
        this.group = group;
    }

    public String getGroup() {
        return group;
    }
}

and then make ClientDataSer and a new class:然后创建 ClientDataSer 和一个新类:

public class ClientDataNewSer extends ClientDataParentSer {

    int member;

    public ClientDataNewSer(String group, int member) {
        super(group);
        this.member = member;
    }

    public int getMember() {
        return member;
    }

    public void setMember(int member) {
        this.member = member;
    }
}

extend this parent class, we can have a list of ClientDataParentSer that contain both, ie the list the output json file needs.扩展这个父类,我们可以有一个包含两者的 ClientDataParentSer 列表,即输出 json 文件需要的列表。

the class for the new object is shown below:新对象的类如下所示:

import java.io.Serializable;
import java.util.ArrayList;

public class ClientNewSer implements Serializable {
    ArrayList<ClientDataParentSer> client;
    ArrayList<ClientDataParentSer> client2;

    public ClientNewSer(ArrayList<ClientDataParentSer> client, ArrayList<ClientDataParentSer> client2) {
        this.client = client;
        this.client2 = client2;
    }

    public ArrayList<ClientDataParentSer> getClient() {
        return client;
    }

    public void setClient(ArrayList<ClientDataParentSer> client) {
        this.client = client;
    }

    public ArrayList<ClientDataParentSer> getClient2() {
        return client2;
    }

    public void setClient2(ArrayList<ClientDataParentSer> client2) {
        this.client2 = client2;
    }
}

Any questions about anything comment below.有任何问题请在下方评论。

The full project is on my github here整个项目是在我的github这里

Your expected JSON string is not normal because any JSON objects belong to the same JSON array should have the same structure, so the output JSON string should look like as below:您预期的 JSON 字符串不正常,因为属于同一个 JSON 数组的任何 JSON 对象都应该具有相同的结构,因此输出的 JSON 字符串应如下所示:

{
  "client":[
    {
      "member":12,
      "group":"g1"
    },
    {
      "member":17,
      "group":"g2"
    },
    {
      "member":29,
      "group":"all"
    }
  ],
  ...
}

If your expected JSON string can be revised so, then here comes another way to achieve what you want by following steps with Jackson and Lambda Expression (since Java 8):如果您可以修改预期的 JSON 字符串,那么这里有另一种方法来实现您想要的内容,方法是使用JacksonLambda Expression (自 Java 8 起)执行以下步骤:

Step 1第1步
Create POJOs and use @JsonAnySetter to serialize client and client2 to List<ClientInfo> , and use @JsonIgnore for getName() for deserialization to ignore field name .创建POJO和使用@JsonAnySetter序列化clientclient2List<ClientInfo> ,和使用@JsonIgnoregetName()为反序列化忽略字段name

class RootPojo {
    private List<ClientInfo> clients = new ArrayList<>();

    @JsonAnySetter
    public void setClients(String name, List<ClientInfo> client) {
        client.forEach(e -> {
            e.setName(name);
        });
        this.clients.addAll(client);
    }

    //general getter and toString
}

class ClientInfo {
    private String name;
    private int member;
    private String group;

    @JsonIgnore
    public String getName() {
        return name;
    }

    //general getters, setters and toString
}

Step 2第2步
Serialize JSON string to pre-defined POJOs with Jackson :使用Jackson JSON 字符串序列化为预定义的 POJO:

ObjectMapper mapper = new ObjectMapper();
RootPojo rootPojo = mapper.readValue(inputJsonStr, RootPojo.class);
System.out.println(rootPojo.toString());

Console output:控制台输出:

RootPojo [clients=[ClientInfo [name=client, member=12, group=g1], ClientInfo [name=client, member=17, group=g2], ClientInfo [name=client2, member=14, group=g11], ClientInfo [name=client2, member=175, group=g22]]] RootPojo [clients=[ClientInfo [name=client, member=12, group=g1], ClientInfo [name=client, member=17, group=g2], ClientInfo [name=client2, member=14, group=g11], ClientInfo [name=client2, member=175, group=g22]]]

Step 3第 3 步
Use Lambda Expression for grouping and summation which will also add the results as new JSON objects back to original JSON string.使用Lambda Expression进行分组和求和,这也会将结果作为新的 JSON 对象添加回原始 JSON 字符串。

rootPojo.getClients()
    .stream()
    .collect(Collectors.groupingBy(ClientInfo::getName,
            Collectors.summingInt(ClientInfo::getMember)))
    .forEach((k,v) -> {
        ClientInfo clientInfo = new ClientInfo();
        clientInfo.setName(k);
        clientInfo.setGroup("all");
        clientInfo.setMember(v);
        rootPojo.getClients().add(clientInfo);
    });
System.out.println(rootPojo.toString());

Console output:控制台输出:

RootPojo [clients=[ClientInfo [name=client, member=12, group=g1], ClientInfo [name=client, member=17, group=g2], ClientInfo [name=client2, member=14, group=g11], ClientInfo [name=client2, member=175, group=g22], ClientInfo [name=client, member=29, group=all], ClientInfo [name=client2, member=189, group=all]]] RootPojo [clients=[ClientInfo [name=client, member=12, group=g1], ClientInfo [name=client, member=17, group=g2], ClientInfo [name=client2, member=14, group=g11], ClientInfo [name=client2, member=175, group=g22], ClientInfo [name=client, member=29, group=all], ClientInfo [name=client2, member=189, group=all]]]

Step 4第四步
Transform rootPojo into Map<String, List<ClientInfo> then deserialize it to output JSON string:rootPojo转换为Map<String, List<ClientInfo>然后将其反序列化以输出 JSON 字符串:

Map<String, List<ClientInfo>> clientMap = new HashMap<>();
rootPojo.getClients().forEach(e -> {
    if (clientMap.containsKey(e.getName())) {
        clientMap.get(e.getName()).add(e);
    } else {
        List<ClientInfo> clients = new ArrayList<>();
        clients.add(e);
        clientMap.put(e.getName(), clients);
    }
});

String outputJsonStr = mapper.writeValueAsString(clientMap);
System.out.println(outputJsonStr);

Console output:控制台输出:

{"client":[{"member":12,"group":"g1"},{"member":17,"group":"g2"},{"member":29,"group":"all"}],"client2":[{"member":14,"group":"g11"},{"member":175,"group":"g22"},{"member":189,"group":"all"}]} {"client":[{"member":12,"group":"g1"},{"member":17,"group":"g2"},{"member":29,"group":" all"}],"client2":[{"member":14,"group":"g11"},{"member":175,"group":"g22"},{"member":189,"组":"所有"}]}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM