Search code examples
javalambdajava-8java-stream

How to write lambda streams function to work with jsonobject with different keys and json array


I'm very new to Java 8 lambdas... I want to write a lambda function that takes a JSONArray, goes over its JSONObjects and creates a Json object of certain field.

For example, a function that takes the JSONArray:

"students": [
    {
            "name": "tom",
            "section": "A",
            "language":"english"
        
    },
    {
            "name": "john",
            "section": "B",
            "language":"dutch"
    },
    {
           "name": "sam",
            "section": "C",
            "language":"spanish"
    }]

My output should be like-

nameJson : {"english":"tom","dutch":"john","spanish":"sam"}
sectionJson: {"english":"A","dutch":"B","spanish":"C"}
JSONArray notification=json.optJSONArray("studentData");
JSONObject nameJson = new JSONObject();
JSONObject sectionJson=new JSONObject();
for (int i=0;i<notification.length();i++){
    nameJson.put(notification.getJSONObject(i).get("language").toString(),notification.getJSONObject(i).get("name").toString());
    sectionJson.put(notification.getJSONObject(i).get("language").toString(),notification.getJSONObject(i).getString("section").toString());
    
}

Please help me out to write using lambda and streams


Solution

  • Simple way to convert a for loop into Stream is to use IntStream with forEach method. The solution defers based on the version of JSON Library that you are using. Older version throws exception that needs to be handled within the Lambda, something like below:

    JSONObject nameJson = new JSONObject();
    JSONObject sectionJson=new JSONObject();
    IntStream.range(0, notification.length()).forEach(index -> {
        try {
            nameJson.put(notification.getJSONObject(index).get("language").toString(),notification.getJSONObject(index).get("name").toString());
            sectionJson.put(notification.getJSONObject(index).get("language").toString(),notification.getJSONObject(index).get("section").toString());
        } catch (JSONException e) {
            throw new RuntimeException(e);
        }
    });
    
    

    Newer version of the JSON Library does not throw Exception on get method, sample code that works with org.json:json:20230227 version looks like below:

    JSONObject nameJson = new JSONObject();
    JSONObject sectionJson=new JSONObject();
    IntStream.range(0, notification.length()).mapToObj(notification::getJSONObject).forEach(jsonObject -> {
        nameJson.put(jsonObject.getString("language"),jsonObject.getString("name"));
        sectionJson.put(jsonObject.getString("language"),jsonObject.getString("section"));
    });
    

    For performing reverse, assuming that you have nameJson and sectionJson objects handy you can try something like (works with latest version of org.json:json):

    List<JSONObject> jsonObjectList = nameJson.keySet().stream().map(language -> {
        JSONObject notificationJson = new JSONObject();
        notificationJson.put("name", nameJson.getString(language));
        notificationJson.put("section", sectionJson.getString(language));
        return notificationJson.put("language", language);
    }).collect(Collectors.toList());
    JSONArray notificationsJson = new JSONArray().putAll(jsonObjectList);