2013-03-27 4 views
0

Уловкой является построение строки Key, как если бы это было пространство имен. Выполнение этого с рекурсией - это моя текущая реализация, но я уверен, что есть более удобные для стека параметры (LINQ? Iterative?), Которые я еще не смог найти. Почти каждый пример слишком прост и не учитывает возможность «импровизировать» их на основе ключевой иерархии.Самый эффективный способ сглаживания вложенного словаря?

Вот краткий пример макета моего словаря. Надеюсь, это достаточно легко понять - я хотел быть основательным.

преобразовать 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

Не могли бы вы предоставить код? Трудно прочитать выше –

+1

Почему вы не храните «entity.foo.bar.baz.title» в качестве ключа внутри одного словаря? Если это невозможно, вы можете представить пример запроса, как бы вы запрашивали свою иерархию. – duedl0r

+0

@ duedl0r Вложен, потому что библиотека ключей очень большая и отправляется в виде JSON. Вложение значительно уменьшает количество передаваемых данных. – erodewald

ответ

0

Это просто простой treewalk. Рекурсивная реализация должна выглядеть примерно так:

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

+0

'SelectMany()' выравнивает коллекцию коллекций. Он не знает, как ходить сколь угодно глубоко. Вы можете заменить рекурсию на стек, но вы все равно должны пройти дерево произвольной глубины и построить свой составной ключ, когда вы спуститесь. Однако я добавил альтернативное, более «LINQY» решение. –

Смежные вопросы