0
\$\begingroup\$

This is the json

[
  {
    "SUBTASK": {
      "id": 10,
      "name": "TestMap",
      "description": "",
      "version":"1.0"
    }
  },
  {
    "SUBTASK": {
      "id": 23,
      "name": "TestMap",
      "description": "",
      "version":"2.0"
    }
  },
  {
    "SUBTASK": {
      "id": 12,
      "name": "Tree",
      "description": "",
      "version":"13.0"
    }
  },
  {
    "SUBTASK": {
      "id": 32,
      "name": "Tree",
      "description": "",
      "version":"10.0"
    }
  }
]

Need to get latest among the number of SUBTASKS ie. filter the latest versions of SUBTASK with respected to name.

So the final json will be like:

final:[{"SUBTASK":{"id":12.0,"name":"Tree","description":"","version":"13.0"}},{"SUBTASK":{"id":23.0,"name":"TestMap","description":"","version":"2.0"}}]

I achived using the below the java code :

Java Snippet

 public void getLatest(String json) throws Exception {
        // converting json to java Object
        List<Map<String, Object>> taskList = new Gson().fromJson(json, new TypeToken<List<Map<String, Object>>>() {
        }.getType());

        Map<String, Object> taskVersionedMap = new HashMap<String, Object>();

        for (int i = 0; i < taskList.size(); i++) {
            Map<String, Object> processMap = taskList.get(i);
            Map<String, Object> process = (Map<String, Object>) processMap.get("SUBTASK");

            String process_name = process.get("name").toString() + "_" + process.get("version");
            taskVersionedMap.put(process_name, processMap);

            for (Map.Entry<String, Object> entry : taskVersionedMap.entrySet()) {
                String[] split = entry.getKey().split("_");
                double version = Double.parseDouble(split[1]);
                String name = split[0];
                for (Map.Entry<String, Object> entry2 : taskVersionedMap.entrySet()) {
                    String[] split_2 = entry2.getKey().split("_");
                    double version_2 = Double.parseDouble(split_2[1]);
                    String name_2 = split_2[0];
                    if (name.equals(name_2)) {
                        if (version < version_2) {
                            String removedProcessName = name + "_" + version;
                            taskVersionedMap.put(removedProcessName, "ignored");
                        }
                    }
                }

            }
        }
        List<Map<String, Object>> filteredVersionList = new ArrayList<Map<String, Object>>();
        for (Map.Entry<String, Object> mapValues : taskVersionedMap.entrySet()) {
            if (!mapValues.getValue().toString().equals("ignored")) {
                try {
                    filteredVersionList.add((Map<String, Object>) mapValues.getValue());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        System.out.println("final:"+new Gson().toJson(filteredVersionList));

    }

The above code gives accurate result expected and is time consuming.

But is it possible to optimize the code since real data json at process will be verry big almost 500 more subtasks

\$\endgroup\$
2
\$\begingroup\$

First of all, you have a grouping operation by process name, then you have the task of finding the maximum by version number per group.

Thus, instead of using nested loops and somehow mashing it all together, simply perform those operations.

As standard operations like grouping and finding a maximum are alreay presenet in the java stream api, all we need is a few helpers to extract the name and the version:

Function<Map<String, Object>, String> extractName = m -> (String) ((Map<String, Object>) m.get("SUBTASK")).get("name");
ToDoubleFunction<Map<String, Object>> extractVersion = m -> Double.parseDouble((String) ((Map<String, Object>) m.get("SUBTASK")).get("version"));

Then, first group by name:

Map<String, List<Map<String, Object>>> byName = taskList.stream()
    .collect(Collectors.groupingBy(extractName));

... which gives you a list of each task type in the value lists.

Now, we can disregard the grouping keys and extract the maximum per list:

List<Map<String, Object>> result = byName.values().stream()
    .map(l -> l.stream().max(Comparator.comparingDouble(extractVersion)))
    .map(Optional::get)
    .collect(Collectors.toList());

Note: the stream.max returns an optional, which would be unset for an empty list. As we cannot generate empty lists here, it is save to simply map via Optional::get to retrieve the value.

All is left is to encode the result list back to json, e.g.

String jsonResult = new GsonBuilder().setPrettyPrinting().create().toJson(result);

Note however, that you should better use a method which operates directly on the data structures, i.e. input and output are List<Map<String, Object>> and another outer wrapper method to do the decoding and encoding. Do one thing in a method.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.