2

I have been trying to sort a JSONArray using Java 8's Stream api. However I guess I couldn't get the type casting done right.

The far I could get is the following piece of code.,

String objects = "[\n" +
                    "  {\n" +
                    "    \"lat\": \"-16.408545\",\n" +
                    "    \"lon\": \"-71.539105\",\n" +
                    "    \"type\": \"0\",\n" +
                    "    \"distance\": \"0.54\"\n" +
                    "  },\n" +
                    "  {\n" +
                    "    \"lat\": \"-16.4244317845\",\n" +
                    "    \"lon\": \"-71.52562186\",\n" +
                    "    \"type\": \"1\",\n" +
                    "    \"distance\": \"1.87\"\n" +
                    "  },\n" +
                    "  {\n" +
                    "    \"lat\": \"-16.4244317845\",\n" +
                    "    \"lon\": \"-71.52562186\",\n" +
                    "    \"type\": \"1\",\n" +
                    "    \"distance\": \"0.22\"\n" +
                    "  }\n" +
                    "  {\n" +
                    "    \"lat\": \"-16.4244317845\",\n" +
                    "    \"lon\": \"-71.52562186\",\n" +
                    "    \"type\": \"1\",\n" +
                    "    \"distance\": \"2.69\"\n" +
                    "  }\n" +
                    "]";
            JSONArray objectsArray = (JSONArray) new JSONParser().parse(objects);

            objectsArray.stream().sorted(Comparator.comparing(a -> ((JSONObject) a).get("distance")));

I get the following error.

Error:(42, 62) java: incompatible types: inferred type does not conform to upper bound(s)
        inferred: java.lang.Object
        upper bound(s): java.lang.Comparable<? super java.lang.Object>

I also referred this question. But I feel that this could be done in an easier way with streams. Any Ideas? I use the following dependency for JSONObject

    <dependency>
        <groupId>com.googlecode.json-simple</groupId>
        <artifactId>json-simple</artifactId>
        <version>1.1</version>
    </dependency>
1
  • Which JSONArray class are you using? For example, I found javax.json.JSONArray that extends List<JsonValue>, not List<JsonObject>, which your code seems to expect. Commented Dec 21, 2017 at 12:07

2 Answers 2

5

Probably you are looking for code like this:

objectsArray.stream().sorted(
    Comparator.comparing(a ->  Double.valueOf((String)((JSONObject) a).get("distance")))
).forEach(o -> System.out.println(o));

The casts that we are using are the following:

((JSONObject) a).get("distance")) //to get the distance as an Object

and then

((String) ((JSONObject) a).get("distance"))) // this Object is actually a String, so cast to it

and then

Double.valueOf((String)((JSONObject) a).get("distance")) //this String, however, is a double, and we want to compare the double size, not alphabetically 

Cause you'd need to compare based on the double value of the distance.

However, there are multiple things to improve. As we are using OOP here, it probably makes sense to at least convert the "String" stream to some objects that'd make sense.

EDIT:

Here's how you probably should have done it:

//define a class to conform with OOP stuff
public static class Coordinate {

    private final Double lat;
    private final Double lon;
    private final Integer type;
    private final Double distance;

    public Coordinate(Double lat, Double lon, Integer type, Double distance){
        this.lat = lat;
        this.lon = lon;
        this.type = type;
        this.distance = distance;
    }

    public Double getDistance() {
        return distance;
    }
}

// define a conversion logic
private static Coordinate convert(JSONObject raw){
    Double distance = Double.valueOf((String) raw.get("distance"));
    Double lon = Double.valueOf((String) raw.get("lon"));
    Double lat = Double.valueOf((String) raw.get("lat"));
    Integer type = Integer.valueOf((String) raw.get("type"));
    return new Coordinate(lat, lon, type, distance);
}

then your method is as easy as writing:

List<JSONObject> coordinates = (List<JSONObject>)new JSONParser().parse(objects);
List<Coordinate> sortedCoordinates = coordinates
                .stream()
                .map(raw -> convert(raw))
                .sorted(Comparator.comparing(Coordinate::getDistance))
                .collect(Collectors.toList());

Another tip I have for you is using a better library like https://github.com/FasterXML/jackson for your object mapping.

Sign up to request clarification or add additional context in comments.

2 Comments

.map(raw -> convert(raw)) can even be replaced with .map(ClassWithConvertMethod::convert)
@Lino yes, I didn't want to put my className as I was not sure if it wouldn't have confused the OP.
2

Try this.

JSONArray objectsArray = (JSONArray) new JSONParser().parse(OBJECTS);
List<JSONObject> jo = (List<JSONObject>) objectsArray.parallelStream()
                .sorted(Comparator.comparing((t) -> Double.parseDouble(((JSONObject) t).get("distance").toString())))
                .collect(Collectors.toList());

System.out.println(JSONArray.toJSONString(jo));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.