c# - 通过辅助键在嵌套字典中查找项目
问题描述
这是我的问题:我有一个嵌套字典(主键:orderIds,辅助键:productIds)。
我的方案:
Dictionary<string, Dictionary<string, List<Task>>>
我需要查找productId
并返回该值(Task
对象)。
一个产品密钥通常不会出现在多个订单中。所以它是独一无二的。
这是一个json示例:
{
"O1": {
"P1": [
{
"Field": "V1"
},
{
"Field": "V7"
}
],
"P2": [
{
"Field": "V2"
},
{
"Field": "V8"
}
]
},
"O2": {
"P1": [
{
"Field": "V3"
},
{
"Field": "V5"
}
],
"P2": [
{
"Field": "V4"
},
{
"Field": "V6"
}
]
}
}
如果我寻找 productId "P5" 我想得到......
[{"Field":"V5"}]
我发现运行的唯一方法是......
return base.Values.Single(x => x.ContainsKey(productId))[productId];
// base是嵌套字典
但我不喜欢我在这里所做的。因为我从存在键的集合(值)中分离了正确的字典,最后我通过键过滤(集合 [键])仅获取值。
这基本上是两个步骤,但我怀疑有一种更简单的方法,只需一步。- 我就是找不到这个。
也许你能帮帮我。:)
解决方案
对于性能调优,请使用 HashSet 而不是 List。我也可以推荐 ISBN:0321637003(LINQ to Objects),也许有更新版本。但无论如何它仍然是非常好的内容。如果您的字典中有数百万个条目,您可以尝试 PLINQ。
返回 base.Values.Single(x => x.ContainsKey(productId))[productId];
Sample json 会引发异常,因为您的 productId (P1, P2) 不是唯一的且 P5 不存在。
如果我寻找 productId "P5" 我想得到... [{"Field":"V5"}] 没有 P5
我不确定它是否有帮助,但这是我的示例代码。我已将您的 json 放入一个文件并对其进行反序列化。
var lFile = new FileInfo(@"C:\_test\data.json");
using var lReader = lFile.OpenText();
var lJsonStr = lReader.ReadToEnd();
var lDicDic = JsonConvert.DeserializeObject<Dictionary<string, Dictionary<string, List<ProductId>>>>(lJsonStr);
//var lTest1 = lDicDic.Values.Single(x => x.ContainsKey("P1"))["P1"]; //Not working, P1 is not unique!
var lTest2 = lDicDic["O2"]["P1"];
//contains => "Field": "V3" + "Field": "V5"
var lTest3 = lDicDic
.SelectMany(p => p.Value.Values.SelectMany(qItem => qItem))
.FirstOrDefault(qProducts => qProducts.Field == "V5");
//contains => "Field": "V5"
var lTest4 = lDicDic["O2"]["P1"].Last();
//contains => "Field": "V5"
编辑:
在您的 Fiddler 代码之后,我能够对其进行测试。
public List<MyTask> GetByProductId(string productId)
{
var lProductDict = Tasks.Values.SingleOrDefault(x => x.ContainsKey(productId));
return lProductDict?.GetValueOrDefault(productId);
}
我的胃告诉我,你目前的方法很难改进;)如果你有很多关于这个嵌套字典的调用,并且它的变化不是很频繁,那么在开始时将字典从 TopDown 重构为 BottomUp 可能是有意义的处理。
无论如何,如果我的评论有帮助,请支持我的回答:)
如果我是你,我会用真实数据制作一些测试用例。不要忘记:如果您处于调试模式,请在项目中启用“优化代码”。在我的测试用例中,没有优化代码的 AVG 为 47ms,优化代码为 42ms:
你可以试试 PLINQ: https ://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/introduction-to-plinq
这是我的测试场景:
var lStopWatch = new Stopwatch();
lStopWatch.Restart();
var lJobs = new Jobs("F1");
const int TestOrderCount = 1000000;
const int TestAvgCount = 1000;
for (var lIndex = 1; lIndex < TestOrderCount; lIndex++)
{
var lNoStr = lIndex.ToString("D6");
lJobs.Add($"O{lNoStr}", $"P{lNoStr}", $"V{lNoStr}");
}
var GetTimes = new List<long>();
var lRandom = new Random();
var lTestCases = Enumerable
.Range(1, TestAvgCount - 1)
.Select(r => $"P{lRandom.Next(1, TestOrderCount - 1):D6}")
.ToList();
var lSetupTimeMs = lStopWatch.ElapsedMilliseconds;
Debug.WriteLine($"SetupTimeMs: {lSetupTimeMs}");
foreach (var lTestCase in lTestCases)
{
lStopWatch.Restart();
var lTest = lJobs.GetByProductId(lTestCase);
GetTimes.Add(lStopWatch.ElapsedMilliseconds);
}
var lAvg = GetTimes.Sum() / TestAvgCount; //AVG Ms per get
Debug.WriteLine($"AVG: {lAvg}");
推荐阅读
- node.js - 使用 PUSH 时不理解 node.js 结果
- mysql - MySQL - 返回行号,其中 value=3
- keras - Hidden and cell state of Keras LSTM
- swift - 对于使用 Swift 的目标,构建设置必须设置为受支持的值
- javascript - 在离子日历应用程序中设置周六和周日不可点击
- php - 根据启用或禁用的多个模块状态对用户的页面访问
- php - PHP Arrays,foreach 无法访问完整的数组元素
- javascript - Jquery Datatable:在这里我们再次使用 Excel 等水平滚动
- prolog - 在 Prolog 中选择独特的元素
- javascript - 如何访问禁用的按钮