我有一个JSON对象,它看起来像
{
"results": [
{
"id": "abc456",
"groups": [
{
"parent_group": null,
"type": "D"
},
{
"parent_group": null,
"type": "DEPARTMENT"
}
],
"examples": [
{
"id": "e13b1e97-31e3-46e6-9d8f-9776c52e5ce0",
"date": "2020-05-10T00:00:00Z"
},
{
"id": "bd31d475-6137-4409-8d17-535f1bf94071",
"date": "2021-05-11T00:00:00Z"
},
{
"id": "0e0806ba-56f6-4527-8fd7-7e0061e30783",
"date": "2019-05-11T00:00:00Z"
}
]
},
{
"id": "def456",
"groups": [
{
"parent_group": null,
"type": "D"
},
{
"parent_group": null,
"type": "D"
}
],
"examples": [
{
"id": "e13b1e97-31e3-46e6-9d8f-9776c52e5ce0",
"date": "2020-05-10T00:00:00Z"
},
{
"id": "bd31d475-6137-4409-8d17-535f1bf94071",
"date": "2021-05-11T00:00:00Z"
},
{
"id": "0e0806ba-56f6-4527-8fd7-7e0061e30783",
"date": "2019-05-11T00:00:00Z"
}
]
}
]
}
我必须对result对象中示例数组中的项进行排序,并以JSON line format的格式返回它们。
我现在拥有的解决方案迭代结果对象中的每个数组,并按日期对示例数组进行排序,然后替换
var jsonlBuilder = new StringBuilder();
var serializer = JsonSerializer.CreateDefault(new JsonSerializerSettings { DateTimeZoneHandling = DateTimeZoneHandling.Utc });
using (var textWriter = new StringWriter(jsonlBuilder))
using (var jsonWriter = new JsonTextWriter(textWriter) { Formatting = Formatting.None })
{
foreach (var obj in jsonArray)
{
var employments = obj.SelectToken("examples");
if (employments.Count() > 1)
{
var b = employments.ToObject<JArray>().OrderBy(c => c.SelectToken("date").ToObject<DateTime>(serializer));
var newEmploymentArray = new JArray(b);
obj["examples"].Replace(newEmploymentArray);
}
obj.WriteTo(jsonWriter);
jsonWriter.WriteWhitespace("\n");
}
}
这不是很好。如果没有if (employments.Count() > 1)
块中的代码,则需要大约6ms,如果有if块,则需要30ms。有没有更好的办法?
2条答案
按热度按时间jyztefdp1#
使用所示的JSON,您的代码的性能并不像您所说的那么差。我看到:
演示小提琴#1 here。
话虽如此,你可以做一些改进:
1.将所有工作移到
OrderBy()
之外,因为通常情况下,比较将被调用n*log(n)
次。1.使用
JToken
indexer而不是SelectToken()
。索引器只需要字典查找,而SelectToken()
将首先将传入的字符串解析为JSONPath组件,然后根据当前标记评估每个组件,最终执行相同的字典查找。1.不是为每个
"date"
值调用序列化器,而是通过使用DateTimeZoneHandling.Utc
+DateParseHandling.DateTime
反序列化JToken
层次结构来仅调用一次序列化器。如果这样做,DateTime
值将在阅读过程中被识别,随后将不需要串行化程序。1.避免克隆JTokens。当执行
employments.ToObject<JArray>()
时,您有效地克隆了数组的内容。无论何时将JToken添加到父令牌而不将其从当前父令牌中删除,您都可以克隆JToken。(参见this answer以了解原因。)1.从文件或流阅读时,请确保直接从流反序列化,而不是加载到中间字符串中,如性能提示中所述:优化内存使用。
还可以考虑直接写入文件,而不是写入中间
StringBuilder
。1.如果你的JSON有一个固定的模式,你可以考虑设计一个相应的数据模型并反序列化它。根据mwatson的11 Ways to Improve JSON Performance & Usage,解析到
JToken
层次结构可能比反序列化到某些数据模型慢20%。把#1 - #5放在一起,你的代码可以重写如下:
或者,使用方法#6,您的数据模型将如下所示:
你的代码:
通过这些更改,我看到两个方法的平均运行时间如下:
Demo fiddle #2 here .
2admgd592#
这个代码对我有用