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);
我有两个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);