例如,我想通过对象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"}]
您可以简单地在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());
我认为这在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
,当然这取决于您的情况。您可能还希望在合并完成后按键对生成的集合进行排序。
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();
我尝试了其中的几个答案,它们只对我起到了部分作用,排序结果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"
}
]