2013-03-27 106 views
0

问题的关键在于如何将Key字符串编译为命名空间。用递归做这件事是我目前的实现,但我确定有更多的栈友好的选项(LINQ?迭代?),我还没有找到。几乎每个例子都太简单了,没有考虑到基于关键层次结构“命名空间”的能力。最有效的方法来拼合嵌套字典?

这是我的词典布局的一个简单例子。希望这很容易理解 - 我想彻底。

我转换JSON与此类似(嵌套,以节省通过有线数据):

"entity": { 
    "foo": { 
     "bar": { 
     "baz": { 
      "2": "description", 
      "1": "title" 
      } 
      } 

进入一个Dictionary<string,object>。当Value is string时,这是“命名空间”的末尾。详细,混淆看看这个对象:

[0] {[entity, Dictionary[String,Object]]} KeyValuePair<string,object> 
    Key "entity" string 
    Value Count = 1 object {Dictionary<string,object>} 
    [0] {[foo, Dictionary[String,Object]]} KeyValuePair<string,object> 
    Key "foo" string 
     Value Count = 12 object {Dictionary<string,object>} 
     [0] {[bar, Dictionary[String,Object]]} KeyValuePair<string,object> 
     Key "bar" string 
     Value Count = 1 object {Dictionary<string,object>} 
      [0] {[baz, Dictionary[String,Object]]} KeyValuePair<string,object> 
      Key "baz" string 
      Value Count = 3 object {Dictionary<string,object>} 
      [0] {[3, title]} KeyValuePair<string,object> 
       Key "3" string 
       Value "title" object {string} 

KeyValuePair将结束是:"entity.foo.bar.baz.title.3", "3"

+0

你能提供代码吗?以上难以阅读 – 2013-03-27 15:50:47

+1

为什么不把“entity.foo.bar.baz.title”作为密钥存储在一本字典中?如果这是不可能的,你可以提供一个查询例子,你将如何查询你的层次结构。 – duedl0r 2013-03-27 15:53:22

+0

@ duedl0r它是嵌套的,因为密钥库非常大,并且以JSON的形式发送。嵌套大大减少了要传输的数据量。 – erodewald 2013-03-27 15:55:10

回答

0

这只是一个简单的树遍历。递归实现应该看起来像这样:

static void Main(string[] args) 
{ 
    Dictionary<string,object> nested = LoadNestedDictionary() ; 
    Dictionary<string,string> flat = new Dictionary<string, string>() ; 
    Flatten(nested,flat) ; 
    return; 
} 

/// <summary> 
/// The wrapper method. Invoke this from your code 
/// </summary> 
/// <param name="input"></param> 
/// <param name="output"></param> 
private static void Flatten(IEnumerable<KeyValuePair<string,object>> input , Dictionary<string,string> output) 
{ 
    foreach (KeyValuePair<string,object> item in input) 
    { 
    string key = item.Key ; 
    object value = item.Value ; 
    if (value is string) 
    { 
     output.Add(key,(string)value) ; 
    } 
    else if (value is Dictionary<string,object>) 
    { 
     Flatten(key , (IEnumerable<KeyValuePair<string,object>>) value , output) ; 
    } 
    else 
    { 
     throw new InvalidOperationException(); 
    } 
    } 
    return ; 
} 

/// <summary> 
/// The core method. Called only from the wrapper method 
/// </summary> 
/// <param name="root"></param> 
/// <param name="input"></param> 
/// <param name="output"></param> 
private static void Flatten(string root , IEnumerable<KeyValuePair<string,object>> input , Dictionary<string,string> output) 
{ 
    foreach (KeyValuePair<string,object> item in input) 
    { 
    string segment = item.Key ; 
    string key  = root + "." + segment ; 
    object value = item.Value ; 
    if (value is string) 
    { 
     string s = (string) value ; 
     output.Add(key,s) ; 
    } 
    else if (value is Dictionary<string,object>) 
    { 
     Dictionary<string,object> d = (Dictionary<string,object>) value ; 
     Flatten(key,d,output); 
    } 
    else 
    { 
     throw new InvalidOperationException(); 
    } 
    } 
    return ; 
} 
+0

正确,我已经使用递归。我很好奇,如果有更简单,更清洁或更有效的方法来做到这一点。我的第一个想法是LINQ的'SelectMany ',但我不确定有可能使用该方法执行密钥命名空间。 – erodewald 2013-03-27 17:39:15

+0

'SelectMany()'展平了一系列的集合。它不知道如何随意漫步。你可以用堆栈替换递归,但是你仍然需要走一个任意深度的树,并在你下降时建立你的组合键。不过,我已经添加了一个替代方案,更多的“LINQY”解决方案。 – 2013-03-27 18:52:30