平面列表到层次结构

时间:2011-01-14 17:53:28

标签: linq hierarchical-data

我最难将列表(Of Folder)转换为层次结构。

Public Class Folder

Public Property FolderID() As Integer
Public Property Name() As String
Public Property ParentFolderID() As Integer
Public Property Children() as IEnumerable(Of Folder)

End Class

我需要返回包含子项的List(Of Folder)。

我从数据库中的数据构建一个List(Of Folder)。

{1,“文件夹1”,没什么} {2,“文件夹2”,1} {3,“文件夹3”,2} {4,“文件夹4”,3} {5,“文件夹5”,没什么}

我无法弄清楚如何以递归方式将子文件夹移动到其父级的Children属性中。

我想用LINQ做这个。

非常感谢任何帮助。

更新

感谢您的回答,但不是那里。根据你的答案,我想出了几乎可行的。

Dim list = (From folder in folderList Select New Folder() With {
    .FolderID = folder.FolderID, 
    .Name = folder.Name, 
    .ParentFolderID = folder.ParentFolderID, 
    .Children = (From child in folderList 
                 Where child.ParentFolderID = item.FolderID).ToList()}).ToList()

{1, "Root", Nothing}
{2, "Child", 1}
{3, "Grand Child", 2}

我得到了所有三个文件夹的列表:

Root
--Child
Child
--Grand Child
Grand Child

应该是这样的:

Root
--Child
----Grand Child

3 个答案:

答案 0 :(得分:12)

如果您使用ToLookup扩展方法,则很容易。

C#:

var lookup = folderList.ToLookup(f => f.ParentFolderID);

foreach (var folder in folderList)
{
    folder.Children = lookup[folder.FolderID].ToList();
}

var rootFolders = lookup[null].ToList();

VB:

Dim lookup = folderList.ToLookup(Function (f) f.ParentFolderID)

For Each folder In folderList
    folder.Children = lookup(folder.FolderID).ToList()
Next

Dim rootFolders = lookup(Nothing).ToList()

答案 1 :(得分:0)

C#版

var newList = list.Select(o=> 
   new Fodler
   { 
        FodlerID = o.FodlerID,
        Children = list.Where(q => q.ParentId == o.FodlerID),
        Parent = list.FirstOrDefault(q => q.FodlerID == o.ParentID ),
        //Other properties goes here
   });

虽然如果你在例如正确的映射中进行EF,它应该自动完成。

答案 2 :(得分:0)

试试这个扩展方法:

    public static IEnumerable<T> AsHierarchy<T>(this IEnumerable<T> collection,
        Func<T, T> parentSelector, Expression<Func<T, IEnumerable<T>>> childrenSelector, T root = default(T))
    {
        var items = collection.Where(x => parentSelector(x).Equals(root));
        foreach (var item in items)
        {
            var childrenProperty = (childrenSelector.Body as MemberExpression).Member as PropertyInfo;
            childrenProperty.SetValue(item, collection.AsHierarchy(parentSelector, childrenSelector, item), null);
        }
        return items;
    }

然后,您可以像这样使用它:

list.AsHierarchy(x => x.Parent, x => x.Children);