bdog
bdog

Reputation: 90

Sort particular JSON element

I have a JSON string like this:

{
  "name": "NameOfObject",
  "itemsToSort": [
    {
      "name": "ValueB",
      "someProperty": "SomeValue"
    },
    {
      "name": "ValueA",
      "someProperty": "SomeValue"
    },
    {
      "name": "ValueC",
      "someProperty": "SomeValue"
    }
  ],
  "someThing": [
    {
      "name": "ThingB",
      "anotherProperty": "SomeValue"
    },
    {
      "name": "ThingA",
      " anotherProperty": "SomeValue "
    }
  ]
}

I need to sort only the itemsToSort element alphabetically in C#, so it looks like this:

{
  "name": "NameOfObject",
  "itemsToSort": [
    {
      "name": "ValueA",
      "someProperty": "SomeValue"
    },
    {
      "name": "ValueB",
      "someProperty": "SomeValue"
    },
    {
      "name": "ValueC",
      "someProperty": "SomeValue"
    }
  ],
  "someThing": [
    {
      "name": "ThingB",
      "anotherProperty": "SomeValue"
    },
    {
      "name": "ThingA",
      " anotherProperty": "SomeValue "
    }
  ]
}

I found code like this, but it sorts at top level, not itemsToSort

var jObj = (JObject)JsonConvert.DeserializeObject(json);
var props = jObj.Properties().ToList();
foreach (var prop in props)
{
    prop.Remove();
}
foreach (var prop in props.OrderBy(p => p.Name))
{
    jObj.Add(prop);
}
string result = jObj.ToString(Formatting.Indented);

How can I sort only the itemsToSort element?

Upvotes: 1

Views: 713

Answers (1)

Mikhail Tulubaev
Mikhail Tulubaev

Reputation: 4261

If you want to sort only items inside itemsToSort array, you could do the following:

var jObj = (JObject)JsonConvert.DeserializeObject(json);
var itemsToSort = jObj.Property("itemsToSort");

var vals = itemsToSort.Values()
    .OfType<JObject>()
    .OrderBy(x => x.Property("name").Value.ToString())
    .ToList();
itemsToSort.Value = JContainer.FromObject(vals);

string result1 = jObj.ToString(Formatting.Indented);

It will take property itemsToSort from deserialized object, take it values and sort by the string representation of name property. To use it, you should be sure that deserialized object has the required property (itemsToSort), it is array and every item of it has the property name.

Actually, it is very simple and hardcoded solution. If you want to sort every item of array by specific key, you can use the following:

public string SortInnerArrays(JObject jObj, string innerKey)
{
    foreach (var prop in jObj.Properties())
    {
        if (prop.Value.Type == JTokenType.Array)
        {
            var vals = prop.Values()
                .OfType<JObject>()
                .OrderBy(x => x.Property(innerKey).Value.ToString())
                .ToList();
            prop.Value = JContainer.FromObject(vals);
        }
    }

    return jObj.ToString(Formatting.Indented);
}

and usage

var jObj = (JObject)JsonConvert.DeserializeObject(json);
string result1 = SortInnerArrays(jObj, "name");

And this is not an ideal solution, but looks much prettier. If you will want to sort arrays inside array inside root object, you will have to add some recursion for it. In my opinion, you should have a model class to store it's values, and sort it without converting to JObject and passing the name of the field, simply:

var obj = JsonConvert.Deserialize<MyClass>(json);
obj.ItemsToSort = obj.ItemsToSort.OrderBy(x => x.Name).ToList();
var result = JsonConvert.SerializeObject(obj, Formatting.Indented);

Upvotes: 1

Related Questions