0

What is the simple way of querying JSON object instead of writing multiple foreachloops?

Sample JSON

{
    "result_index": 0,
    "results": [
       {
          "final": true,
          "alternatives": [
             {
                "delta": 0.9,
                "timestamps": [
                   [
                      "hi",
                      2.55,
                      2.81
                   ]
                ]
             }
          ]
       }
    ]
}

Is there a way to replace multiple following foreach into single foreach

var rawData = JObject.Parse(responseString);
var results = rawData["results"];

    foreach (var item in results)
     {
         foreach (var alternative in item["alternatives"])
          {
            foreach (var timestamp in alternative["timestamps"])
             {
                           
             }
          }
      }
4
  • 1
    Deserialize it properly, then use SelectMany Commented Jul 15, 2021 at 7:59
  • Currently we don't know the type of results, or which JSON library you're using, which makes it tricky to give a concrete answer. For example, Json.NET supports JSON Path which might help you (see newtonsoft.com/json/help/html/QueryJsonSelectTokenWithLinq.htm) but we don't know if you're using Json.NET or not... Commented Jul 15, 2021 at 8:07
  • @JonSkeet Yes, I'm using Json.NET Commented Jul 15, 2021 at 8:11
  • Right, so please edit the question to make that clear, ideally providing a minimal reproducible example. Commented Jul 15, 2021 at 8:35

2 Answers 2

3

For C# or any other .NET Language I would suggest that you should use the Linq capabilities of the Newtonsoft Library. Have a look at this example here

As an update to @JonSkeet answer here is a set of working code.

class Program
    {
        static void Main(string[] args)
        {
            var sample = JsonConvert.DeserializeObject(File.ReadAllText("SampleJSON.json")) as JObject;

            var timestamps = (from item in sample["results"]
                              from alternative in item["alternatives"]
                              from timestamp in alternative["timestamps"] select timestamp)
                              .SelectMany(t => t);
            foreach(var ts in timestamps)
            {
                var working = ts.ToObject<string>() + " - Hello Ts";
            }

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

4 Comments

Not my downvote, but I suspect it's because the answer is basically just a link. If you'd provided a code example in the answer, ideally showing exactly how the OP could change their current code, that would be a better answer.
I appreciate the point @JonSkeet, but what is the point of reproducing the code that is clearly visible in documentation for the actual product in use.
Because a) links go bad, and b) you can provide an answer that is tailored for the OP's question - which the documentation can't. Put it this way: imagine your current answer side-by-side with an answer which shows how to change the OP's code using LINQ. Which is the better answer? (I might as well just do that myself...)
Now that's a constructive answer @JonSkeet, thanks for the clarifications
1

Two options present themselves. The first would be to use LINQ - you basically want multiple from clauses in a query expression, or call SelectMany. Here's a complete example:

using Newtonsoft.Json.Linq;
using System;
using System.IO;
using System.Linq;

class Program
{
    static void Main(string[] args)
    {
        string json = File.ReadAllText("test.json");
        var rawData = JObject.Parse(json);
        var results = rawData["results"];

        var timestamps = from item in results
                         from alternative in item["alternatives"]
                         from timestampArray in alternative["timestamps"]
                         from timestamp in timestampArray
                         select timestamp;
        foreach (var timestamp in timestamps)
        {
            Console.WriteLine(timestamp);
        }
    }
}

Output:

hi
2.55
2.81

Alternatively, you can use JSON Path with the SelectTokens method. This isn't something I've used before, but the following query works - it just may not be the best way of doing it:

using Newtonsoft.Json.Linq;
using System;
using System.IO;
using System.Linq;

class Program
{
    static void Main(string[] args)
    {
        string json = File.ReadAllText("test.json");
        var rawData = JObject.Parse(json);
        var timestamps = rawData.SelectTokens("$.results[*].alternatives[*].timestamps[*][*]");
        foreach (var timestamp in timestamps)
        {
            Console.WriteLine(timestamp);
        }
    }
}

6 Comments

Thanks Jon, however neither works. The first one throws an error message and second one doesn't iterate
@Aniruddha: "throws an error message" doesn't give me any real information to go on. Hint: if you'd provide a minimal reproducible example as I suggested earlier, I could test it. Better questions lead to better answers... (Note that for the second part, I only said it would be "something like" that JSON Path query - you should do more research for exactly what path expression might be required.)
I've edited the question and code what I currently use. The message I get is that query statement should be followed by select
I've update my original answer with a working example of @JonSkeet sample, hopefully that should get you sorted.
@Aniruddha: That's still not really a minimal reproducible example - ideally I should be able to copy, paste, compile and run, without adding a class wrapper etc. You should be trying to make it as easy as possible for someone to help you. It's definitely much better, and now I'm going to change my answer so it is complete... but please learn from this and ask better questions in the future.
|

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.