2013-03-27 49 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