Считать общий список <T>с родительской / дочерней иерархией в таблицу данных, сохраняя родительскую / дочернюю иерархию - PullRequest
0 голосов
/ 30 мая 2011

Я преобразовал это дерево XML с именами единиц: Тусклый = Размер

Dim1            
|---MG1     
    |---M1  
    |---M2  
    |---M3  
        |---MG31
        |---MG32


Dim2            
|---MG220       
    |---MG2222  

... в список единиц, то есть список, в котором каждая единица может иметь другой список с неограниченной иерархией. Теперь я хочу преобразовать список в табличный формат с родительской / дочерней иерархией.

Таким образом, дата должна выглядеть следующим образом:

Dimension...Parent..Child
Dim1........Dim1....MG1
Dim1........MG1.....M1
Dim1........MG1.....M2
Dim1........Dim1....MG2
Dim1........MG1.....M3
Dim1........M3......MG31
Dim1........M3......MG32
Dim2........Dim2....MG220
Dim2........MG220...MG2222

public class Unit           
{           
   public String Name { get; set; }         
   public Unit Dimension { get; set; }          
   public UnitParent { get; set; }          
   public List<Unit> Children { get; set; }         

}

Вопрос: Как бы вы повторили Список и записали все данные в DataTable? Должен быть хитрый алгоритм, который я не могу найти.

Ответы [ 2 ]

1 голос
/ 03 июня 2011

Рекурсия - это правильный подход, но я собираюсь предложить подход LINQ - тем более, что этот вопрос был помечен с помощью LINQ.

Одна из приятных вещей с LINQ заключается в том, что методы расширения могут убратьмного сложностей и оставляют простые запросы, которые просто выражают бизнес-логику.

Итак, вот что я использую для сглаживания рекурсивных структур:

public static IEnumerable<T> Flatten<T>(this Func<T, IEnumerable<T>> @this, T root)
{
    var head = new [] { root, };
    var tail =
        from c in @this(root)
        where !c.Equals(root)
        from d in @this.Flatten(c)
        select d;
    return head.Concat(tail);
}

Обратите внимание на рекурсивный вызов Flatten, и этоэто метод расширения, определенный для функции, которая возвращает дочерние элементы от данного родительского элемента.

Теперь мы можем определить Func<T, IEnumerable<T>> следующим образом:

Func<Unit, IEnumerable<Unit>> f = u => u.Children;

И затем, предполагая, чтовсе свойства Dimension, Parent и Children не равны NULL, мы можем использовать этот запрос, чтобы создать список записей для добавления в таблицу:

var records =
    from r in dimensions
    from d in f.Flatten(r)
    select new
    {
        Dimension = d.Dimension.Name,
        Parent = d.Parent.Name,
        d.Name,
    };

Теперь, если любой изсвойства null, вот исправление.

Переопределите f как:

Func<Unit, IEnumerable<Unit>> f = u => u.Children ?? new List<Unit>();

И добавьте этот метод расширения:

public static R ValueOrNull<T, R>(this T @this, Func<T, R> selector)
    where R : class
{
    return @this != null ? selector(@this) : null;
}

Теперь запрос работаеткак это:

var records =
    from r in dimensions
    from d in f.Flatten(r)
    select new
    {
        Dimension = d.Dimension.ValueOrNull(x => x.Name),
        Parent = d.Parent.ValueOrNull(x => x.Name),
        d.Name,
    };

Все еще веОчень похоже, но null безопасно.

Надеюсь, это поможет.

0 голосов
/ 30 мая 2011

Простой рекурсивный алгоритм подойдет ...

function AddSubTree(Unit unit) {
  if (unit != unit.Dimension)
    AddItemToDataTable(unit.Dimension.Name, unit.UnitParent.Name, unit.Name);
  foreach (Unit childUnit in unit.Children) {
    AddSubTree(childUnit); 
  }
}

Вы вызываете AddSubTree для каждого имеющегося у вас объекта измерения

...