Json.net:按对象Id合并两个json数组

时间:2015-03-25 11:43:28

标签: c# json json.net

我想通过对象id来破坏json数组,例如。假设我有这个json数组:

 [{"Id":"1", "a":"1", "b":"2"},
  {"Id":"2", "a":"3", "b":"1"},
  {"Id":"3", "a":"5", "b":"1"}]

我想用这个数组突破它

 [{"Id":"1", "a":"32", "b":"42"},
 {"Id":"2", "a":"3", "b":"1", "c":"23"},
  {"Id":"12", "a":"12", "b":"45"}]

预期结果应为:

[{"Id":"1", "a":"32", "b":"42"},
  {"Id":"2", "a":"3", "b":"1", "c":"23"},
  {"Id":"3", "a":"5", "b":"1"},
  {"Id":"12", "a":"12", "b":"45"}]

4 个答案:

答案 0 :(得分:2)

我认为可以在C#中轻松完成。如果您将实体映射到类似的东西:

[DataContract]
public class Entity
{
    [DataMember(Name = "Id")]
    public string Id { get; set; }

    [DataMember(Name = "a")]
    public int? A { get; set; }

    [DataMember(Name = "b")]
    public int? B { get; set; }

    [DataMember(Name = "c")]
    public int? C { get; set; }
}

我认为使用LINQ执行所需的操作是不可能的,但是老的foreach将解决您的问题。

编辑:实际上在看了@ vadim-gremyachev后,我认为可以很好地完成LINQ:

var l1 = JsonConvert.DeserializeObject<IList<Entity>>(
    @"[{""Id"":""1"", ""a"":""1"", ""b"":""2""}, 
       {""Id"":""2"", ""a"":""3"", ""b"":""1""}, 
       {""Id"":""3"", ""a"":""5"", ""b"":""1""}]");

var l2 = JsonConvert.DeserializeObject<IList<Entity>>(
    @"[{""Id"":""1"", ""a"":""32"", ""b"":""42""},
       {""Id"":""2"", ""a"":""3"", ""b"":""1"", ""c"":""23""},
       {""Id"":""12"", ""a"":""12"", ""b"":""45""}]");

// LINQ
var res = l1.Concat(l2).GroupBy(x => x.Id).Select(x => x.Last()).ToList();

// Foraech
var res2 = new List<Entity>(l1);
foreach (var l2Entity in l2)
{
    var resEntity = res2.FirstOrDefault(x => x.Id == l2Entity.Id);
    if (resEntity == null)
    {
        res2.Add(l2Entity);
    }
    else
    {
        res2[res2.IndexOf(resEntity)] = l2Entity;
    }
}

然后你可以将你的res列表序列化回JSON并完成它:

var json = JsonConvert.SerializeObject(res);

生成的JSON将是:

[
    {"Id":"1","a":32,"b":42},
    {"Id":"2","a":3,"b":1,"c":23},
    {"Id":"3","a":5,"b":1},
    {"Id":"12","a":12,"b":45}
]

您也可以使用l1而不创建res,这取决于您的情况。您可能还希望在合并完成后按键对结果集合进行排序。

答案 1 :(得分:1)

您可以在JArray上使用Linq,因为这些是IEnumerable<JToken>

var first = JArray.Parse(@"[{'Id':'1', 'a':'1', 'b':'2'},
            {'Id':'2', 'a':'3', 'b':'1'},
            {'Id':'3', 'a':'5', 'b':'1'}]");


var second = JArray.Parse(@"[{'Id':'1', 'a':'32', 'b':'42'},
            {'Id':'2', 'a':'3', 'b':'1', 'c':'23'},
            {'Id':'12', 'a':'12', 'b':'45'}]");

var resultAsEnumerable = first.Concat(second)
                              .GroupBy(t => t["Id"])
                              .Select(g => g.Last());

如果您需要将结果作为JArray,则可以轻松地将结果转换为结果:

var resultAsJArray = new JArray(resultAsEnumerable.ToArray());

答案 2 :(得分:0)

var x = JArray.Parse(@"[{'Id':'1', 'a':'1', 'b':'2'},
                        {'Id':'2', 'a':'3', 'b':'1'},
                        {'Id':'3', 'a':'5', 'b':'1'}]");


var y = JArray.Parse(@"[{'Id':'1', 'a':'32', 'b':'42'},
                        {'Id':'2', 'a':'3', 'b':'1', 'c':'23'},
                        {'Id':'12', 'a':'12', 'b':'45'}]");

//1. Union arrays skipping items that already exist
x.Merge(y, new JsonMergeSettings
        {
            MergeArrayHandling = MergeArrayHandling.Union,
        });

//2. Get distinct items by key (Id) 
var result = x.GroupBy(i => i["Id"]).Select(g => g.Last()).ToList();

答案 3 :(得分:0)

我尝试了其中的一些答案,但它们只对我有用,将结果 json 排序留给读者练习,您可能希望输入 json 没有 ID 作为字符串以使其正常工作。使用 .net core 3.1 测试。

var input1 = JsonConvert.DeserializeObject<JArray>(@"[  {'Id':'1', 'a':'1', 'b':'2'},
                                                        { 'Id':'2', 'a':'3', 'b':'1'},
                                                        { 'Id':'3', 'a':'5', 'b':'1'}]");

var input2 = JsonConvert.DeserializeObject<JArray>(@" [  {'Id':'1', 'a':'32', 'b':'42'},
                                                         {'Id':'2', 'a':'3', 'b':'1', 'c':'23'},
                                                         {'Id':'12', 'a':'12', 'b':'45'}]");

//you may want this the other way depending on what your trying to do
//input1.Merge(input2);
input2.Merge(input1);

var res = new List<dynamic>();

foreach (var x in input2.GroupBy(x => x["Id"]).ToList())
{
      var newItem = new ExpandoObject();
      foreach (var y in x)
      {
            foreach (JProperty z in y)
            {
                 newItem.TryAdd(z.Name, z.Value);
            }
       }
       res.Add(newItem);

 }

 Console.WriteLine(JsonConvert.SerializeObject(res));
 Console.ReadLine();

输出:

[{
        "Id": "1",
        "a": "32",
        "b": "42"
    }, {
        "Id": "2",
        "a": "3",
        "b": "1",
        "c": "23"
    }, {
        "Id": "12",
        "a": "12",
        "b": "45"
    }, {
        "Id": "3",
        "a": "5",
        "b": "1"
    }
]