1

I've seen all the posts about keeping order in JSONArray, but I couldn't find a solution.

In this post, they said : An array is an ordered collection of values.

But when I create a JSONArray from my List I lost the order and I have to keep it.

I've tried all the solutions, but none of them works for me.

I'm using org.json as JSON lib to create JSONArray and then CDL to create a CSV.

The List contains JSON so I could create a CSV file.

Code :

List<LinkedHashMap<String, Object>> stringObject=new ArrayList<LinkedHashMap<String,Object>>();

for(...; ...;...){
        stringObject.add(map);
    }
/** stringObject is a List containing ordered map */

/** Here I'm trying to create a JSONArray */

JSONARRay jsonArray=new JSONArray(stringObject);

Here the ouput :

The List : [{_id=1, name=Aurelia Menendez, scores.0.type=exam, scores.0.score=60.06045071030959, scores.1.type=quiz, scores.1.score=52.79790691903873, scores.2.type=homework, scores.2.score=71.76133439165544}, {_id=2, name=Corliss Zuk, scores.0.type=exam, scores.0.score=67.03077096065002, scores.1.type=quiz, scores.1.score=6.301851677835235, scores.2.type=homework, scores.2.score=66.28344683278382},{.....}]

The JSONArray : [{"scores.1.type":"quiz","scores.1.score":52.79790691903873,"_id":1,"name":"Aurelia Menendez","scores.0.type":"exam","scores.2.type":"homework","scores.0.score":60.06045071030959,"scores.2.score":71.76133439165544},{"scores.1.type":"quiz","scores.1.score":6.301851677835235,"_id":2,"name":"Corlis ...

As you can see, I lost the order.

So How to keep the right order so I can create a good CSV ?

The map order is respected, but the items order inside a map is not respected.

Edits

Maps I'm adding to the List :

{_id=1, name=Aurelia Menendez, scores.0.type=exam, scores.0.score=60.06045071030959, scores.1.type=quiz, scores.1.score=52.79790691903873, scores.2.type=homework, scores.2.score=71.76133439165544}
{_id=2, name=Corliss Zuk, scores.0.type=exam, scores.0.score=67.03077096065002, scores.1.type=quiz, scores.1.score=6.301851677835235, scores.2.type=homework, scores.2.score=66.28344683278382}
{_id=3, name=Bao Ziglar, scores.0.type=exam, scores.0.score=71.64343899778332, scores.1.type=quiz, scores.1.score=24.80221293650313, scores.2.type=homework, scores.2.score=42.26147058804812}
{_id=4, name=Zachary Langlais, scores.0.type=exam, scores.0.score=78.68385091304332, scores.1.type=quiz, scores.1.score=90.2963101368042, scores.2.type=homework, scores.2.score=34.41620148042529}
{_id=11, name=Marcus Blohm, scores.0.type=exam, scores.0.score=78.42617835651868, scores.1.type=quiz, scores.1.score=82.58372817930675, scores.2.type=homework, scores.2.score=87.49924733328717}
{_id=12, name=Quincy Danaher, scores.0.type=exam, scores.0.score=54.29841278520669, scores.1.type=quiz, scores.1.score=85.61270164694737, scores.2.type=homework, scores.2.score=80.40732356118075}
{_id=15, name=Tambra Mercure, scores.0.type=exam, scores.0.score=69.1565022533158, scores.1.type=quiz, scores.1.score=3.311794422000724, scores.2.type=homework, scores.2.score=45.03178973642521}

Using JSONObject :

JSONObject jsonObject=new JSONObject();
for(LinkedHashMap<String,Object> map:stringObject){

    jsonObject.putAll(map);
    System.out.println(jsonObject);
}

Output :

{"scores.1.type":"quiz","scores.1.score":52.79790691903873,"_id":1,"name":"Aurelia Menendez","scores.0.type":"exam","scores.2.type":"homework","scores.0.score":60.06045071030959,"scores.2.score":71.76133439165544}
{"scores.1.type":"quiz","scores.1.score":6.301851677835235,"_id":2,"name":"Corliss Zuk","scores.0.type":"exam","scores.2.type":"homework","scores.0.score":67.03077096065002,"scores.2.score":66.28344683278382}
{"scores.1.type":"quiz","scores.1.score":24.80221293650313,"_id":3,"name":"Bao Ziglar","scores.0.type":"exam","scores.2.type":"homework","scores.0.score":71.64343899778332,"scores.2.score":42.26147058804812}
{"scores.1.type":"quiz","scores.1.score":90.2963101368042,"_id":4,"name":"Zachary Langlais","scores.0.type":"exam","scores.2.type":"homework","scores.0.score":78.68385091304332,"scores.2.score":34.41620148042529}
{"scores.1.type":"quiz","scores.1.score":82.58372817930675,"_id":11,"name":"Marcus Blohm","scores.0.type":"exam","scores.2.type":"homework","scores.0.score":78.42617835651868,"scores.2.score":87.49924733328717}

Ismail

Community
  • 1
  • 1
Ismail Sen
  • 571
  • 2
  • 14
  • 27
  • 1
    The array is keeping the order. But for some reason you have only one thing in the array, and that thing is an object (which does not preserve order) which has your actual data in it. – user253751 Jul 22 '14 at 10:05
  • @immibis, in the loop I add a `LinkedHashMap` at every iteration. So my list contains several maps. Do you mean that I couldn't have the order when I do the JSONArray ? – Ismail Sen Jul 22 '14 at 10:12
  • I didn't see the `,{...}` at the end of the output, so now I realize you do have multiple maps. What I said still mostly applies - arrays keep order, but objects (maps) don't. And the array retained the order of the objects, and the objects didn't retain the order of their properties. – user253751 Jul 22 '14 at 22:17

4 Answers4

3

Lets look at the below code of yours and understand whats is exactly happening.

JSONObject jsonObject=new JSONObject();
 for(LinkedHashMap<String,Object> map:stringObject){

jsonObject.putAll(map);
System.out.println(jsonObject);
} 

So lets examine whats happening here.... when you call jsonObject.putAll(map).....this is what happens

public JSONObject putAll(Map<String, Object> newProperties)
{
    assert newProperties != null;

    for (Map.Entry<String, Object> e : newProperties.entrySet())
    {
        this.put(e.getKey(), e.getValue());
    }

    return this;
}

This method is iterating over map(in your case Ordered map i.e. LinkedHashMap) one by one and adding it to its own put method with key and value as arguments.

Now let see what happens in put method

public JSONObject put(String key, Object value) throws JSONException {
    if (key == null) {
        throw new NullPointerException("Null key.");
    }
    if (value != null) {
        testValidity(value);
        this.map.put(key, value);
    } else {
        this.remove(key);
    }
    return this;
}

Here it simply puts that key value in its own map which is basically a hashmap in the end. As you know that hash map is not ordered . So thats why when you look at the output of it it is basically not in the order you have inserted.

Paras Mittal
  • 1,159
  • 8
  • 18
  • Changed the loop but did'nt work, same output. The order is not respected, plus I've have a warning : `Type safety: The method putAll(Map) belongs to the raw type HashMap. References to generic type HashMap should be parameterized`when I do : `jsonObject.putAll(stringObject.get(i)`. (I can't use `put`) – Ismail Sen Jul 22 '14 at 11:44
  • If you try with a `map` as I gave in the edits you will notice that it wont work. – Ismail Sen Jul 22 '14 at 11:45
  • @AaronDigulla thanks man. I did google it and found that i was wrong. Foreach iterates in order. – Paras Mittal Jul 22 '14 at 13:38
  • 2
    @ParasMittal I guess you are right. Eventually its gonna be Hashmap so there's no point taking LinkedHashMap as in the end jsonObject will add entry to its Hashmap which does not keeps its order. – nutz Jul 22 '14 at 13:49
1

From your question i think you are not getting the order of insertion same as order of output. I just double checked it and found that you are wrong. I have done the following thing and getting the following output.

/*******************output*************/



[{"val0":"val0"},{"val1":"val1"},{"val2":"val2"},{"val3":"val3"},{"val4":"val4"},{"val5":"val5"},{"val6":"val6"},{"val7":"val7"},{"val8":"val8"},{"val9":"val9"}]

/********************************/

 /************** Code****************/

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;

import org.json.JSONArray;

public class TestOrderArrayList {

public static void main(String[] args) {
    List<LinkedHashMap<String, Object>> stringObject = new ArrayList<LinkedHashMap<String, Object>>();

    for (int i = 0; i < 10; i++) {
        LinkedHashMap<String, Object> hashMap = new LinkedHashMap<String, Object>();
        hashMap.put("val" + i, "val" + i);
        stringObject.add(hashMap);
    }
    /** stringObject is a List containing ordered map */

    /** Here I'm trying to create a JSONArray */

    JSONArray jsonArray = new JSONArray(stringObject);

    System.out.println(jsonArray);
}
}

If there's something else you want to say. please elaborate a little bit.

Hope this solves your query.

Atul Sharma
  • 718
  • 4
  • 11
  • This what I'm doing too, I add a `map` at every iteration. I tried your example and I got the same result as yours. But my example doesn't work, I lost the order once I call `JSONArray` – Ismail Sen Jul 22 '14 at 10:43
  • Could you attach your example. May b there's a minute detail you are missing. – Atul Sharma Jul 22 '14 at 10:46
  • Could please see the **Edits**. I've added the `maps` I use. – Ismail Sen Jul 22 '14 at 10:53
  • 1
    OPs maps have several items in them. The order of maps is correct but the order of items in the maps is randomized. My guess is that `JSONObject` doesn't preserve order. – Aaron Digulla Jul 22 '14 at 11:16
  • @AtulSharma If you try with a `map` as I gave in the edits you will notice that it wont work. – Ismail Sen Jul 22 '14 at 11:49
1

You're looking at the wrong place. The elements of the list stay in order (List and JSONArray keep the order).

But you add maps to the JSONArray. The conversion of the items in each individual map seems to lose the ordering. You can check that by converting just a single map to JSONObject.

To answer how to preserve this order, I need to know which JSON framework you're using.

EDIT You're using the default json.org Java framework. As the documentation clearly states:

A JSONObject is an unordered collection of name/value pairs.

So there is no way to do it with this framework.

I checked jackson but couldn't find any indication that it preserves the sort order of map elements.

My guess is that this is because JavaScript doesn't support this.

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
  • I've mentionned that I'm using `org.json` . Also, I've tried `JSONObject` but it didn't work too. I've added in the **Edits** the output when I use `JSONObject` – Ismail Sen Jul 22 '14 at 11:19
  • It's clear now that the problem came from `items` inside a `map`. The reason I wanna keep them ordered is to create the right `CSV`. Is it possible to keep the items order ? – Ismail Sen Jul 22 '14 at 11:58
  • 1
    I don't think this is possible with JSON. What you can try is to look into the serialization code of your JSON framework and manually serialize the maps, entry by entry. – Aaron Digulla Jul 22 '14 at 12:41
0

According the values you specified in the "Output" section, the JsonArray in the JsonObject is retaining the order [same order maintained in the List Object].

You do not have to worry about the order of JSonElements in your response, as according to the JSON specification they need not be maintained.

For example: JsonString1 = {"id":2,"name":"John"} JsonString2 = {"name":"John","id":2} are exactly the same. i.e if you use org.json classes or Jackson to check equality of the above JsonObjects they will be equal.

On the flipside if you want the same order in your JsonArrays every time you run your program, I suppose you should be using a LinkedList<> instead of a List<>.

sandee609
  • 3
  • 2