Search code examples
c#arraysjsonjson.net

Search an array of arrays of objects with Newtonsoft


I have an array of an array of JToken objects. I would like to return a list of the top 10 objects ordered by the Severity member in descending order; right now, I'm just returning all issues where Severity < 3. I'm stumbling over accessing the inner array. Can anyone give me some guidance on how to query the data with Newtonsoft to get my desired results? TIA!

Some sample data:

[
  [
    {
      "IssueOrderNumber": 1,
      "Description": "Exhaust fumes leaking into Parts department.",
      "Resolution": "Increased outbound ventilation in Service area.",
      "Severity": 1
    }
  ],
  [
    {
      "IssueOrderNumber": 1,
      "Description": "Houston, we have a problem.",
      "Resolution": "We are working on it.",
      "Severity": 1
    },
    {
      "IssueOrderNumber": 2,
      "Description": "We have issues with employee retention.",
      "Resolution": "We will start giving retention bonuses.",
      "Severity": 2
    },
    {
      "IssueOrderNumber": 3,
      "Description": "Increasing incidents of sexual harassment.",
      "Resolution": "Sexual harassment training is now doubled, and an independent investigator/arbitrator has been hired.",
      "Severity": 2
    }
  ],
  [
    {
      "IssueOrderNumber": 1,
      "Description": "Deal worksheet left unattended on salesperson's desk",
      "Resolution": "Salesperson required training hours doubled",
      "Severity": 2
    },
    {
      "IssueOrderNumber": 2,
      "Description": "PII left exposed for customers submitting inquiries over Web",
      "Resolution": "Web site reengineered to encrypt PII",
      "Severity": 2
    },
    {
      "IssueOrderNumber": 3,
      "Description": "A hacker exposed PII for sales staff and managerial staff over the Web.",
      "Resolution": "Web site was patched",
      "Severity": 1
    }
  ]
]

My C#:

jArrIssues2 = JArray.Parse(strJArrIssues);
for (int i = 0; i < jArrIssues2.Count; i++)
{
    for (int j = 0; j < jArrIssues2[i].Count(); j++)
    { 
        JObject iss = JObject.Parse(jArrIssues2[i][j].ToString());
        JObject tmpObj = new JObject();
        int intSev = (int)iss["Severity"];
        string strDescr = (string)iss["Description"];
        if (intSev < 3) // Currently, getting all Sev 1, 2 issues;
                        // I'd rather get the top 10 issues ordered by severity
        { 
            tmpObj.AddFirst(new JProperty("Description", strDescr));
            tmpObj.Property("Description").AddAfterSelf(new JProperty("Severity", intSev));
            jArrUltimate.Add(tmpObj);
        }
    }
}

Solution

  • I'd recommend creating a class Issue, and using the Newtonsoft converter to put the JSON string into the class structure. It will be much easier to deal with.

    Then you can make use of LINQ functions to sort, filter, or limit your results.

    Note that I de-serialize into a List<List<Issue>>. That is because of the JSON structure you defined in your original post. It's an odd structure; you may want to look at simplifying it.

    The selectMany LINQ call below will reduce the list of lists to a single list, making it easier to traverse.

    See example code below.

    public class Issue {
        public int IssueOrderNumber { get; set; }
        public string Description { get; set; }
        public string Resolution { get; set; }
        public int Severity { get; set; }
    }
    
    
    string json = @"[
        [
            {
            ""IssueOrderNumber"": 1,
            ""Description"": ""Exhaust fumes leaking into Parts department."",
            ""Resolution"": ""Increased outbound ventilation in Service area."",
            ""Severity"": 1
            }
        ],
        [
            {
            ""IssueOrderNumber"": 1,
            ""Description"": ""Houston, we have a problem."",
            ""Resolution"": ""We are working on it."",
            ""Severity"": 1
            },
            {
            ""IssueOrderNumber"": 2,
            ""Description"": ""We have issues with employee retention."",
            ""Resolution"": ""We will start giving retention bonuses."",
            ""Severity"": 2
            },
            {
            ""IssueOrderNumber"": 3,
            ""Description"": ""Increasing incidents of sexual harassment."",
            ""Resolution"": ""Sexual harassment training is now doubled, and an independent investigator/arbitrator has been hired."",
            ""Severity"": 2
            }
        ],
        [
            {
            ""IssueOrderNumber"": 1,
            ""Description"": ""Deal worksheet left unattended on salesperson's desk"",
            ""Resolution"": ""Salesperson required training hours doubled"",
            ""Severity"": 2
            },
            {
            ""IssueOrderNumber"": 2,
            ""Description"": ""PII left exposed for customers submitting inquiries over Web"",
            ""Resolution"": ""Web site reengineered to encrypt PII"",
            ""Severity"": 2
            },
            {
            ""IssueOrderNumber"": 3,
            ""Description"": ""A hacker exposed PII for sales staff and managerial staff over the Web."",
            ""Resolution"": ""Web site was patched"",
            ""Severity"": 1
            }
        ]
    ]";
    
    // convert json to C# object
    List<List<Issue>> issues = JsonConvert.DeserializeObject<List<List<Issue>>>(json);
    
    // get the top 10 severe issues using linq
    List<Issue> topSevereIssues = issues.SelectMany(r => r).OrderByDescending(r => r.Severity).Take(10).ToList(); 
    
    // turn back to JSON (if thats the final desired data format)
    string topSevereIssuesJson = JsonConvert.SerializeObject(topSevereIssues);