I have two jsons data: 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 },
]
I want Json1's quantity subtract Json2's quantity based on same "name"
The result will return all the Json1's items plus another property "differ".
[
{"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 },
]
It takes about 2 seconds for input data(Json1 and Json2) have more than 3000-5000 items for each when using the solution below.Looking for a new solution with BETTER performance. Say less than 1 second with around 5000 items.
C# Code:
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);
}
I've tested it using your method and a different method using dictionaries. You can find it as a dotnetfiddle here: 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; }
}
}
In DotNetFiddle, it seems like your method is quicker (approximately factor 5 to 10). However, running it locally in LINQPad, variant 2 runs up to twice as fast.
I assume, it will depend a lot on your input, and how many iterations you will have. But, as Jon Skeet suggested: It is always best to actually try it out. That's what tools like LINQPad were developed for :-)
UPDATE:
Also, not using JsonConvert.SerializeObject(...)
to generate the resulting JSON, but instead just creating it manually will also boost your performance. However, I would not recommend this, unless your Json structure remains as simple as you have described. In my tests, this saved about 30%. Example implementation:
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);