2013-04-02 4 views
2

Я пытаюсь извлечь из серии строк, которая представляет глубину, как:Jagged словарь динамической глубины?

'foo/bar/x' 
'foo/bar/baz/x' 
'foo/bar/baz/x' 
'foo/bar/lol/x' 

Где x это число не волнует. Я дошел до разделения на / и прокручивался, и в этот момент на PHP я бы сделал что-то вроде проверки, где в цикле я (используя for (i=0; etc)), а затем использую это, чтобы определить мою глубину для построения выходного массива как:

output['foo']['bar'] = 1 
output['foo']['bar']['baz'] = 2 
output['foo']['bar']['lol'] = 1 

Проблема есть «глубина» является динамической и может быть либо только 3/4 глубоко (что я мог бы просто объяснить с большим количеством проверок стоимости i и обращение с ними отдельно) или сказать 10 или более глубоко, и в этом случае, вероятно, лучше всего рекурсивная функция.

Я столкнулся с проблемой, что для строки в качестве индекса массива мне нужно использовать словарь, но вам нужно указать типы в словаре, то есть вам нужно знать глубину в расширенном (исправьте меня если я ошибаюсь) при создании экземпляра словарного объекта.

Я предполагаю, что атака может быть чем-то вроде вызова рекурсивной функции, так что каждый раз, когда она вызывается, вы передаете i, чтобы указать глубину, тогда функция вызывает себя, декременяя i каждый раз, пока она не построит часть дерева из этого но это структуры хранения, которые я использую для этого в C#, о котором я не уверен.

Конечный результат будет CSV, что я могу открыть в виде таблицы выглядеть следующим образом:

Foo  0 
|__Bar  1 
    |__Baz 2 
    |__Lol 1 

Возможно одно направление для решения заключается в использовании чистого C# массив и просто хранить название (например, foo) там, сохраняя информацию из показаний массива, что, вероятно, является наилучшей практикой. Благодарю.

+0

Даже в PHP , Если 'output ['foo'] ['bar'] = 1', как можно' output ['foo'] ['bar'] ['baz'] 'существуют? Либо 'output ['foo'] ['bar']' является словарем, либо является значением. Я не говорю, что это невозможно, но это не очень хорошая идея ... рассмотрите также: 'var whatAmI = output ['foo'] ['bar'];', 'whatAmI == 1'? 'whatAmI - Словарь'? – Kobi

ответ

5

Вы можете создать свой собственный класс со следующими членами:

class Directory 
{ 
    public int Value { get; set; } 
    public Dictionary<string, Directory> SubDirectories { get; set; } 
} 

Хранить ваши данные, используя его, а затем рекурсивно экспортировать в CSV.

Чтобы получить output["foo"]["bar"] синтаксис можно реализовать индексатор в классе:

public Directory this[string name] 
{ 
    get { return SubDirectories.ContainsKey("name") ? SubDirectories[key] : null; } 
    set { SubDirectories.Add(name, value); } 
} 
+0

Возможно, было бы проще реализовать какую-то структуру данных дерева. – Romoku

+1

Это какое-то дерево, где свойство 'SubDirectories' содержит листья, не так ли? – MarcinJuraszek

+0

Ну, в подкаталоге нет ссылки на его родителя. – Romoku

2

Хотя решение Marcin Juraszek велик, я просто хочу, чтобы расширить свой ответ только немного с dynamic сахаром. Дело не в том, что это решение будет соответствовать вашим потребностям, а просто рассмотрит его как пример. Я сделаю Directory<T> родовым, так что вы можете использовать любой тип для value (обратите внимание, что из-за динамической природы у меня есть один бросок в реализации (T)value)

class Directory<T> : DynamicObject 
{ 
    private T Value; 
    private Dictionary<string, Directory<T>> SubDirectories; 

    public Directory() 
    { 
     SubDirectories = new Dictionary<string, Directory<T>>(); 
    } 

    public override bool TryGetMember(GetMemberBinder binder, out Object result) 
    { 
     if (!SubDirectories.ContainsKey(binder.Name)) 
      SubDirectories[binder.Name] = new Directory<T>(); 

     result = SubDirectories[binder.Name]; 
     return true; 
    } 

    public override bool TrySetMember(SetMemberBinder binder, Object value) 
    { 
     if (!SubDirectories.ContainsKey(binder.Name)) 
      SubDirectories[binder.Name] = new Directory<T>(); 

     SubDirectories[binder.Name].Value = (T)value; 
     return true; 
    } 

    public override string ToString() 
    { 
     return Value.ToString(); 
    } 
} 

И теперь вы можете использовать dynamic функцию, доступную из C 4 #.0

dynamic dir = new Directory<string>(); 

dir.foo = "Foo Value"; 
dir.foo.bar = "Bar Value"; 
dir.foo.bar.baz = "baz value"; 
dir.foo.bar.Lol = "Lol value"; 

Console.WriteLine(dir.foo.bar.Lol); //will print Lol value 
Console.WriteLine(dir.foo.bar.baz); //will print baz value 

который:

Foo  Foo Value 
|__Bar  Bar Value 
    |__Baz baz value 
    |__Lol Lol value 

вы также можете переопределить TryGetIndex и TrySetIndex, так что вы можете передать сложные строки, которые не могут быть использованы в качестве свойств в C#

+0

Использование 'ToString' - это мошенничество, не так ли? Кроме того, у вас не может быть каталога под названием «Value» или «SubDirectories». Далее, мы можем даже уйти: 'public static implicit operator T (Directory m) {return m.Value;}' будет включать 'string s = dir.foo.bar;'. Как я уже сказал в комментарии - это не очень хорошая идея ... – Kobi

+1

@ Kobi Хорошо, вы определенно должны сделать внутреннюю структуру приватной, а затем вы можете 'dir.SubDirectories =" Foo Value ";'. Кроме того, неявный оператор T - не лучшая идея, но опять же динамика сложна при интеграции со статическими структурами. Я использую 'Value.ToString()', поэтому внутреннее 'Value' может иметь сложную логику в' ToString'. Во всяком случае, я заметил, что это всего лишь демонстрация или пример, а не производственный код. –