Neo
Neo

Reputation: 16239

Is there a simple way to find out lowest value from JSON without doing de-serialization?

I have below JSON output from API. I want to find out lowest value among all elements.

JSON data:

{
  "prices": [   
    {
      "frequency": "daily",
      "date": "2020-05-05",
      "intraperiod": false,
      "open": 295.06,
      "high": 301.0,
      "low": 294.46,
      "close": 297.56
    },
    {
      "frequency": "daily",
      "date": "2020-05-04",
      "intraperiod": false,
      "open": 289.17,
      "high": 293.69,
      "low": 112.1,
      "close": 293.16
    },
    {
      "frequency": "daily",
      "date": "2020-05-01",
      "intraperiod": false,
      "open": 286.25,
      "high": 299.0,
      "low": 222,
      "close": 289.07
    }
  ]
}

I want to compare all values among JSON element and display lowest value = "low": 112.1 and its own high value. "high": 293.69,

I tried like below using jQuery, but how can I do it in C#?

function get(arr, prop) {
    var min;
    for (var i=0 ; i<arr.length ; i++) {
        if (min== null || parseInt(arr[i][prop]) > parseInt(min[prop]))
            min= arr[i];
    }
    return min;
}

var min = get(arr, "low");
console.log(min.high);

Upvotes: 0

Views: 776

Answers (4)

Pavel Anikhouski
Pavel Anikhouski

Reputation: 23278

You may use Newtonsoft.Json.Linq for that, parse your JSON to JObject, then get all properties with low name, find the property with lowest value and get the high value at the same level

var json = JObject.Parse(jsonString);

var properties = json.DescendantsAndSelf()
    .OfType<JProperty>()
    .Where(p => p.Name == "low");

 var lowProperty = properties
     .Aggregate((p1, p2) => p1.Value.Value<double>() < p2.Value.Value<double>() ? p1 : p2);

var highProperty = (lowProperty?.Parent as JObject)?.Property("high");
Console.WriteLine(lowProperty);
Console.WriteLine(highProperty);

It gives you

"low": 112.1
"high": 293.69

Upvotes: 2

RoadRunner
RoadRunner

Reputation: 26335

You could create classes to represent your JSON using a tool like quicktype.io:

public partial class Temperatures
{
    [JsonProperty("prices")]
    public List<Price> Prices { get; set; }
}

public partial class Price
{
    [JsonProperty("frequency")]
    public string Frequency { get; set; }

    [JsonProperty("date")]
    public DateTimeOffset Date { get; set; }

    [JsonProperty("intraperiod")]
    public bool Intraperiod { get; set; }

    [JsonProperty("open")]
    public double Open { get; set; }

    [JsonProperty("high")]
    public double High { get; set; }

    [JsonProperty("low")]
    public double Low { get; set; }

    [JsonProperty("close")]
    public double Close { get; set; }
}

Then deserialize your json using Json.NET, and use MinBy from MoreLinq to get the minimum prices by Low. MinBy will return a IEnumerable<Price>, so we can iterate each min price and print the Low and High properties:

using Newtonsoft.Json;
using MoreLinq;

...

var deserializedJson = JsonConvert.DeserializeObject<Temperatures>(json);

var minPrices = deserializedJson.Prices.MinBy(price => price.Low);

foreach (var price in minPrices)
{
    Console.WriteLine($"Min = {price.Low}, High = {price.High}");
}

Output:

Min = 112.1, High = 293.69

Full demo on dotnetfiddle.net

Upvotes: 1

Štefan Bartoš
Štefan Bartoš

Reputation: 404

You could use regex.

var pattern = "\"high\": ([0-9]+(\\.[0-9]+)?)";
MatchCollection matches = Regex.Matches(json, pattern);

var max = double.MinValue;
foreach (Match m in matches) {
    var val = Convert.ToDouble(m.Groups[1].Value);
    if (max < val) {
        max = val;
    }           
}

Same for low value.

Upvotes: 1

Shehroze Malik
Shehroze Malik

Reputation: 181

De-serializing it would be the way to go

you can de-serialize it into an object and do the calculations you want

    // <auto-generated />
//
// To parse this JSON data, add NuGet 'Newtonsoft.Json' then do:
//
//    using QuickType;
//
//    var priceData = PriceData.FromJson(jsonString);

namespace QuickType
{
    using System;
    using System.Collections.Generic;

    using System.Globalization;
    using Newtonsoft.Json;
    using Newtonsoft.Json.Converters;

    public partial class PriceData
    {
        [JsonProperty("prices")]
        public List<Price> Prices { get; set; }
    }

    public partial class Price
    {
        [JsonProperty("frequency")]
        public string Frequency { get; set; }

        [JsonProperty("date")]
        public DateTimeOffset Date { get; set; }

        [JsonProperty("intraperiod")]
        public bool Intraperiod { get; set; }

        [JsonProperty("open")]
        public double Open { get; set; }

        [JsonProperty("high")]
        public double High { get; set; }

        [JsonProperty("low")]
        public double Low { get; set; }

        [JsonProperty("close")]
        public double Close { get; set; }
    }

    public partial class PriceData
    {
        public static PriceData FromJson(string json) => JsonConvert.DeserializeObject<PriceData>(json, QuickType.Converter.Settings);
    }

    public static class Serialize
    {
        public static string ToJson(this PriceData self) => JsonConvert.SerializeObject(self, QuickType.Converter.Settings);
    }

    internal static class Converter
    {
        public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
        {
            MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
            DateParseHandling = DateParseHandling.None,
            Converters =
            {
                new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }
            },
        };
    }
}

you can use Quciktype to get POCO class from the json (The above code is from generated from that)

Then use

var data = PriceData.FromJson(json_string);
var min = data.Select(x=>x.Low).Min();
// There may be multiple Price objects with the same low, I will use the first one
min_object = data.Where(x=>x.Low == min).First()
var high_value_of_min_object = min_object.High;

You may want to decide what element you are looking for P.S I have not tested the code.

Upvotes: 2

Related Questions