c#不同深度的嵌套字典

标签 c# dictionary switch-statement nested control-structure

本质上,我需要的是将不同的 int 变量映射到字典。或者至少那是我想做的方式。我能想到的最简单的方法是使用 switch 语句来解释我想要的内容。

string s = "";
int a = 1;
int b = 2;
int c = 0;

switch (a){
    case 0:
        s = "a0";
        break;
    case 1:
        switch (b){
            case 0:
                s = "b0";
                break
            case 1:
                switch (c){
                    case 0:
                        s = "c0";
                        break;
                    case 1:
                        s = "c1";
                        break;
                }
                break
            case 2:
                s = "b2";
                break;
        }
        break;
    case 2:
        s = "a2";
        break;
}

为简洁起见,这是一个简化版本,否则您可能会有很多嵌套,并且在不止一种情况下等等。我在想一个很好的解决方案是使用字典来快速选择正确的值,但这并不能很好地嵌套,因为嵌套字典的大部分内部嵌套都不需要有值。

我首先想到字典的原因是因为类似于以下的声明语法会很好(这类似于字典的字典)。

thing = {
    {0, "a0"},
    {1, {
            {0, "b0"},
            {1, {
                    {0, "c0"}, 
                    {1, "c1"}
                }
            },
            {2, "b2"}
        }
    },
    {2, "a2"}
}
// Next line is sort of hopeful but potentially unrealistic syntax
s = thing[a][b][c]; // or  = thing(a,b,c);

编辑:这不是必需的声明语法,但它简短易懂,这正是我正在寻找的。

编辑:或 LINQ,我已经看到很多针对类似问题的 LINQ 建议,但我并不是特别熟悉它。

最佳答案

鉴于您正在寻找键的部分匹配项,您将无法使用单个字典来完成此任务。原因如下:

假设您有某种“规则”类。我们称它为“ key ”。您可以像这样实例化它:

Key.Create(0) // this "rule" would match any query key starting with 0 (e.g., {0}, {0, 1}, or {0, 1, 9, 2, 23, 243})

现在假设您想使用某种“事实”或“查询键”类来查询它。由于您使用在 Add 操作期间用作键的值类型查询字典,因此您将不得不重用相同的类型:

Key.Create(0, 2, 13) // this fact should be matched by rules {0}, {0,2} or {0, 2, 13}

现在您将尝试获取值:

var value = map[Key.Create(0, 2, 13)]

Key 类可以覆盖 Equals 以允许部分键匹配。但是,字典将首先使用哈希码,而 Key.Create(0, 2, 13) 的哈希码永远不会与 Key.Create(0) 的哈希码相匹配。您也无法通过使用任何类型的基础/派生类型来解决这个问题。

最好的选择可能是推出自己的类(class)。应该这样做:

class ResultMap
{
    public void Add(int[] key, string value)
    {
        Debug.Assert(key != null);
        Debug.Assert(key.Length > 0);

        var currentMap = _root;
        foreach (var i in key.Take(key.Length - 1))
        {
            object levelValue;
            if (currentMap.TryGetValue(i, out levelValue))
            {
                currentMap = levelValue as Dictionary<int, object>;
                if (currentMap == null)
                    throw new Exception("A rule is already defined for this key.");
            }
            else
            {
                var newMap = new Dictionary<int, object>();
                currentMap.Add(i, newMap);
                currentMap = newMap;
            }
        }
        var leaf = key[key.Length - 1];
        if (currentMap.ContainsKey(leaf))
            throw new Exception("A rule is already defined for this key.");
        currentMap.Add(leaf, value);
    }

    public string TryGetValue(params int[] key)
    {
        Debug.Assert(key != null);
        Debug.Assert(key.Length > 0);

        var currentMap = _root;
        foreach (var i in key)
        {
            object levelValue;
            if (!currentMap.TryGetValue(i, out levelValue))
                return null;
            currentMap = levelValue as Dictionary<int, object>;
            if (currentMap == null)
                return (string) levelValue;
        }

        return null;
    }

    private readonly Dictionary<int, object> _root = new Dictionary<int, object>();
}

这是一个单元测试:

    public void Test()
    {
        var resultMap = new ResultMap();
        resultMap.Add(new[] {0}, "a0");
        resultMap.Add(new[] {1, 0}, "b0");
        resultMap.Add(new[] {1, 1, 0}, "c0");
        resultMap.Add(new[] {1, 1, 1}, "c1");
        resultMap.Add(new[] {1, 2}, "b2");
        resultMap.Add(new[] {2}, "a2");

        Debug.Assert("a0" == resultMap.TryGetValue(0));
        Debug.Assert("a0" == resultMap.TryGetValue(0, 0));
        Debug.Assert("a0" == resultMap.TryGetValue(0, 1));
        Debug.Assert("a0" == resultMap.TryGetValue(0, 2));
        Debug.Assert("a0" == resultMap.TryGetValue(0, 0, 0));
        Debug.Assert("a0" == resultMap.TryGetValue(0, 0, 1));
        Debug.Assert("a0" == resultMap.TryGetValue(0, 0, 2));
        Debug.Assert("a0" == resultMap.TryGetValue(0, 1, 0));
        Debug.Assert("a0" == resultMap.TryGetValue(0, 1, 1));
        Debug.Assert("a0" == resultMap.TryGetValue(0, 1, 2));
        Debug.Assert("a0" == resultMap.TryGetValue(0, 2, 0));
        Debug.Assert("a0" == resultMap.TryGetValue(0, 2, 1));
        Debug.Assert("a0" == resultMap.TryGetValue(0, 2, 2));
        Debug.Assert(null == resultMap.TryGetValue(1));
        Debug.Assert("b0" == resultMap.TryGetValue(1, 0));
        Debug.Assert(null == resultMap.TryGetValue(1, 1));
        Debug.Assert("b2" == resultMap.TryGetValue(1, 2));
        Debug.Assert("b0" == resultMap.TryGetValue(1, 0, 0));
        Debug.Assert("b0" == resultMap.TryGetValue(1, 0, 1));
        Debug.Assert("b0" == resultMap.TryGetValue(1, 0, 2));
        Debug.Assert("c0" == resultMap.TryGetValue(1, 1, 0));
        Debug.Assert("c1" == resultMap.TryGetValue(1, 1, 1));
        Debug.Assert(null == resultMap.TryGetValue(1, 1, 2));
        Debug.Assert("b2" == resultMap.TryGetValue(1, 2, 0));
        Debug.Assert("b2" == resultMap.TryGetValue(1, 2, 1));
        Debug.Assert("b2" == resultMap.TryGetValue(1, 2, 2));
        Debug.Assert("a2" == resultMap.TryGetValue(2));
        Debug.Assert("a2" == resultMap.TryGetValue(2, 0));
        Debug.Assert("a2" == resultMap.TryGetValue(2, 1));
        Debug.Assert("a2" == resultMap.TryGetValue(2, 2));
        Debug.Assert("a2" == resultMap.TryGetValue(2, 0, 0));
        Debug.Assert("a2" == resultMap.TryGetValue(2, 0, 1));
        Debug.Assert("a2" == resultMap.TryGetValue(2, 0, 2));
        Debug.Assert("a2" == resultMap.TryGetValue(2, 1, 0));
        Debug.Assert("a2" == resultMap.TryGetValue(2, 1, 1));
        Debug.Assert("a2" == resultMap.TryGetValue(2, 1, 2));
        Debug.Assert("a2" == resultMap.TryGetValue(2, 2, 0));
        Debug.Assert("a2" == resultMap.TryGetValue(2, 2, 1));
        Debug.Assert("a2" == resultMap.TryGetValue(2, 2, 2));
    }

关于c#不同深度的嵌套字典,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16925497/

相关文章:

c# - 在 .NET Speech 中添加另一个声音

c# - 如果与开关速度

java - 理解带有 "&"符号的 Switch 语句

vba - 不区分大小写的字典

python - 将嵌套的json转换成没有嵌套对象的字典格式

java - 在 Android 应用程序的导航菜单内创建一个警报对话框以注销

c# - 如何将 AWS ASP.NET Core 日志记录添加到 ASP.NET Core 2.0 Razor Pages 应用程序?

c# - 反射发射 : how to Convert Attribute instance to CustomAttributeBuilder or CustomAttributeData

c# - 如何使用 NPOI 在 C# 中使用列名获取 excel 单元格值

Java 8 List<V> 到 Map<K, V> 与函数