-3

I am using System.Text.Json and right now, I'm trying to figure out how to sort a JsonArray without deserializing it, if that is at all possible. I have been able go get other LINQ functions to work with JsonArrays, however, I cannot seem to get OrderBy to work and I am getting compile errors with everything I have tried.

When I set a var to be the result of the sorted array, VS says that it is:

IOrderedEnumerable<JsonNode>

VS will not allow me to convert this type to a JsonArray. If I use JsonArray instead of var, then I get the red squiggly lines and the error says:

CS0029: Cannot implicitly convert type 'System.Linq.IOrderedEnumerable<System.Text.Json.Nodes.JsonNode>' to System.Text.Json.Nodes.JsonArray

I have been looking all around and I have not had much luck when it comes to sorting JsonArrays. Is this even possible?

Below are some of the things I have tried:

private void SortArrayTest(JsonArray arrayToSort)
{
    var sortedArray0 = arrayToSort.OrderBy(x => x["Name"].ToString());
    JsonArray sortedArray1 = arrayToSort.OrderBy(x => x["Name"]);
    JsonArray sortedArray2 = arrayToSort.OrderBy(x => x["Name"].ToString());
    JsonArray sortedArray3 = arrayToSort.OrderBy(x => x["Name"].ToString()).ToArray();
    JsonArray sortedArray4 = arrayToSort.OrderBy(x => x["Name"].ToString()).ToList();
    JsonArray sortedArray5 = arrayToSort.OrderBy(x => x["Name"].ToString()).ToList<string>();
    JsonArray sortedArray6 = arrayToSort.OrderBy(x => (string)x["Name"]).ToArray();
}
NateLFO
  • 9
  • 2
  • Use newtonsoft.json. Nobody knows how system.text.json works. It is very tricky. – Serge May 12 '22 at 16:47
  • OrderBy doesn't sort in place, it returns a new ordered enumerable. Do you want to sort in place, or do you want to return a new `JsonArray`? – dbc May 12 '22 at 16:50
  • *Nobody knows how system.text.json works* - an interesting and bold claim, Serge.. – Caius Jard May 12 '22 at 17:03
  • @dbc, Honestly, it doesn't really matter as long as it works. I know OrderBy doesn't sort in place, hence my code example above where I was setting new JsonArrays to equal the result of the sorting. I'm just trying to figure out if I have to deserialize, or if sorting can be done without deserializing. – NateLFO May 12 '22 at 17:03
  • @CaiusJard Thanks for your remark. See my answer as an explanation – Serge May 12 '22 at 17:30

3 Answers3

0

Enumerable.OrderBy() does not sort the incoming sequence in-place. Instead it returns a new IEnumerable<T> that, when iterated, returns the items of the original sequence in the required order. Thus to modify the contents of your JsonArray you will have to clear it and re-add the ordered items, like so:

private static void SortArrayTest(JsonArray arrayToSort)
{
    var sortedList = arrayToSort.OrderBy(x => x["Name"].ToString()).ToList();
    arrayToSort.Clear();
    foreach (var item in sortedList)
        arrayToSort.Add(item);
}

Or, if you would prefer to create a new array and leave the original unchanged, you may serialize the ordered enumerable via JsonSerializer.SerializeToNode() like so:

private static JsonArray SortNewArrayTest(JsonArray arrayToSort) =>
    JsonSerializer.SerializeToNode(arrayToSort.OrderBy(x => x["Name"].ToString())).AsArray();

Notes:

  • A JsonNode knows its parent container (JsonArray or JsonObject) via its Parent property. Thus it's not possible for a given JsonNode to belong to two parents at once.

    This explains why it is necessary to serialize the ordered enumerable to a new sequence of nodes, rather than simply materializing the ordered enumerable as an array and creating a new JsonArray from it that contains the existing nodes.

  • JsonSerializer.SerializeToNode() (new in .NET 6) is the equivalent of Newtonsoft's JToken.FromObject().

Demo fiddle here.

dbc
  • 104,963
  • 20
  • 228
  • 340
  • It's kind of weird though, because you can sort an array without having to enumerate through it. If you set up a simple list of Names and IDs and then sort them like so: personList = personList.OrderBy(x => x.Name).ThenBy(x => x.Id).ToList(), then it works just fine. That doesn't mean that this applies to JsonArrays, just with normal collections. – NateLFO May 12 '22 at 17:13
  • @NateLFO - `ToList()` returns a new list though. Or maybe you are surprised that you can't add a `JsonNode` to two `JsonArray`'s at once? If so I added an explanation for that. – dbc May 12 '22 at 17:16
  • Thanks. I’m still learning C# and just started messing with JSON about a week ago, so I still have a lot to learn. – NateLFO May 12 '22 at 17:39
  • *without having to enumerate through it* - what do you think `.ToList()` does? :) – Caius Jard May 12 '22 at 18:20
  • *just started messing with JSON about a week ago* - make life easy; have classes, serialize and deserialize them as a graph of objects. Right now you've done the equivalent of buying an electric bicycle and you're riding it to work by standing on the tire and walking backwards so it goes forwards, It'd be a lot easier to just pedal it with the electric assist – Caius Jard May 12 '22 at 18:22
  • @Caius Jard - What I meant was not having to do a for each loop and add each item to the new array, you can just set the new array/list to equal the ordered .ToList. Now that I know how to do this directly in the JsonArray, I did some testing, and yes, deserialzing to a C# list and then sorting is much faster than trying to sort the JsonArray directly. I was just trying to learn what can be done and what’s the best way to do it. – NateLFO May 12 '22 at 19:55
0

try this

private JsonArray SortArrayTest(JsonArray arrayToSort)
{
return  (JsonArray)  Nodes.JsonArray.Parse(JsonSerializer
.Serialize(arrayToSort.OrderBy(x => (string) x["Name"])));
}

IMHO, it is better to use Newtonsoft.Json. In this case your code would be much more simple and readable

private JArray SortArrayTest(JArray arrayToSort)
{
 return JArray.FromObject(arrayToSort.OrderBy(x => (string)x["Name"]));
}
Serge
  • 40,935
  • 4
  • 18
  • 45
0

Some of you have provided some very helpful comments on how to sort a JsonArray directly, and after trying the recommendations, while they do work, it seems that it is much faster in terms of processing time to deserialize the JsonArray to a C# list, then sort, then re-serialize back to Json.

E_net4
  • 27,810
  • 13
  • 101
  • 139
NateLFO
  • 9
  • 2
  • 2
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community May 13 '22 at 08:54