c# 根据另一个 属性 的相同值从另一个 json 的 属性 int 值中减去另一个

c# Subtract one json's property int value from another based on another property's same value

我有两个jsons数据: Json1:

[
{"name":"a1", "quantity": 10 },
{"name":"a2", "quantity": 11 },
{"name":"a3", "quantity": 12 },
{"name":"a4", "quantity": 13 },
{"name":"a5", "quantity": 14 },
]

Json2:

[
{"name":"a1", "quantity": 11 },
{"name":"b1", "quantity": 1 },
{"name":"b2", "quantity": 12 },
{"name":"a3", "quantity": 13 },
{"name":"a5", "quantity": 14 },
]

我希望 Json1 的数量减去 Json2 的数量基于相同的“名称”

结果将 return Json1 的所有项目加上另一个 属性“不同”。

[
{"name":"a1", "quantity": 10, "differ": -1 },
{"name":"a2", "quantity": 11, "differ": 11  }, // "a2" is not in Json2, so "differ" will be 11
{"name":"a3", "quantity": 12, "differ": -1 },
{"name":"a4", "quantity": 13, "differ": 13 },
{"name":"a5", "quantity": 14, "differ": 0 },
]

输入数据(Json1 和 Json2)大约需要 2 秒,每个数据项超过 3000-5000 项时使用解决方案 below.Looking 以获得性能更好的新解决方案。说不到 1 秒,大约 5000 个项目。
C# 代码:

public string GetDiff(string json1, string json2)
{
            var json1Array = JArray.Parse(json1);
            var json2Array = JArray.Parse(json2);
            var json3Array = new JArray();
            foreach (var item in json1Array)
            {
                var name = (string) item["name"];
                var quantity = (int) item["quantity"];
                var differ = quantity;
                var itemJson2 = json2Array.Where(it => (string) it["name"] == name).FirstOrDefault();
                if (itemJson2 != null)
                {
                    differ = quantity - (int) itemJson2["quantity"];
                }
                json3Array.Add(new JObject() { { "name", name }, { "quantity", quantity }, { "differ", differ } });
            }
            result = JsonConvert.SerializeObject(json3Array);

}

我已经使用您的方法和使用字典的不同方法对其进行了测试。您可以在此处将其作为 dotnetfiddle 找到:https://dotnetfiddle.net/rS0Am8

using System;
using System.Diagnostics;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

public class Program
{
    public void Main()
    {
        var json1 = @"[
        {""name"":""a1"", ""quantity"": 10 },
        {""name"":""a2"", ""quantity"": 11 },
        {""name"":""a3"", ""quantity"": 12 },
        {""name"":""a4"", ""quantity"": 13 },
        {""name"":""a5"", ""quantity"": 14 },
        ]";
        var json2 = @"[
        {""name"":""a1"", ""quantity"": 11 },
        {""name"":""b1"", ""quantity"": 1 },
        {""name"":""b2"", ""quantity"": 12 },
        {""name"":""a3"", ""quantity"": 13 },
        {""name"":""a5"", ""quantity"": 14 },
        ]";
        var retries = 10000;

        var sw = new Stopwatch();

        sw.Start();

        string result = "";

        for (var i = 0; i < retries; i++)
        {
            var json1Array = JArray.Parse(json1);
            var json2Array = JArray.Parse(json2);
            var json3Array = new JArray();
            foreach (var item in json1Array)
            {
                var name = (string) item["name"];
                var quantity = (int) item["quantity"];
                var differ = quantity;
                var itemJson2 = json2Array.Where(it => (string) it["name"] == name).FirstOrDefault();
                if (itemJson2 != null)
                {
                    differ = quantity - (int) itemJson2["quantity"];
                }
                json3Array.Add(new JObject() { { "name", name }, { "quantity", quantity }, { "differ", differ } });
            }
            result = JsonConvert.SerializeObject(json3Array);
        }

        sw.Stop();
        Console.WriteLine("Variant 1 (" + sw.ElapsedMilliseconds + "ms)");
        Console.WriteLine(result);

        sw.Restart();
        for (var i = 0; i < retries; i++)
        {
            var d1 = JsonConvert.DeserializeObject<JsonData[]>(json1).ToDictionary(d => d.Name, d => d.Quantity);
            var d2 = JsonConvert.DeserializeObject<JsonData[]>(json2).ToDictionary(d => d.Name, d => d.Quantity);

            result = JsonConvert.SerializeObject(d1.Select(kvp => new JsonResultData
            {
                Name = kvp.Key,
                Quantity = kvp.Value,
                Differ = d2.ContainsKey(kvp.Key) ? kvp.Value - d2[kvp.Key] : kvp.Value
            }));
        }

        sw.Stop();
        Console.WriteLine("Variant 2 (" + sw.ElapsedMilliseconds + "ms)");
        Console.WriteLine(result);
    }

    // Define other methods and classes here
    class JsonData
    {
        [JsonProperty("name", Order = 1)]
        public string Name { get; set; }

        [JsonProperty("quantity", Order = 2)]
        public int Quantity { get; set; }
    }

    class JsonResultData : JsonData
    {
        [JsonProperty("differ", Order = 3)]
        public int Differ { get; set; }
    }
}

在 DotNetFiddle 中,您的方法似乎更快(大约 5 到 10 倍)。但是,运行 它在 LINQPad 本地运行,变体 2 的运行速度是原来的两倍。

我想,这在很大程度上取决于您的输入,以及您将进行多少次迭代。但是,正如 Jon Skeet 所建议的:实际尝试总是最好的。这就是像 LINQPad 这样的工具的开发目的:-)

更新:

此外,不使用 JsonConvert.SerializeObject(...) 生成结果 JSON,而是手动创建它也会提高您的性能。但是,我不推荐这样做,除非您的 Json 结构仍然像您描述的那样简单。在我的测试中,这节省了大约 30%。示例实现:

sw.Restart();
for (var i = 0; i < retries; i++)
{
    var d1 = JsonConvert.DeserializeObject<JsonData[]>(json1).ToDictionary(d => d.Name, d => d.Quantity);
    var d2 = JsonConvert.DeserializeObject<JsonData[]>(json2).ToDictionary(d => d.Name, d => d.Quantity);

    var sb = new StringBuilder();
    sb.Append("[");
    foreach (var kvp in d1)
    {
        sb.AppendFormat("{{\"name\":\"{0}\",\"quantity\":{1},\"differ\":{2}}}",
            kvp.Key.Replace("\"", "\\""),
            kvp.Value.ToString(CultureInfo.InvariantCulture),
            (d2.ContainsKey(kvp.Key) ? kvp.Value - d2[kvp.Key] : kvp.Value).ToString(CultureInfo.InvariantCulture));
    }
    sb.Append("]");
    result = sb.ToString();
}

sw.Stop();
Console.WriteLine("Variant 3 (" + sw.ElapsedMilliseconds + "ms)");
Console.WriteLine(result);