1

我有一个嵌套评论列表,它们基本上形成了一个树。

//Non-Relevant properties (Like Body, Creator etc) excluded
internal class Comment
{
    public int ID { get; set; }
    public int ItemID { get; set; }
    public int ParentItemID { get; set; }
    public List<Comment> ChildComments { get; set; }
}

首先,我Posts从数据库中获取列表,然后获取所有Comments where ItemID == Posts[all].id

我想遍历一个平面列表并创建一个嵌套或树列表。

它是这样的:

如果ParentItemID == 0,那么我们有一个顶级评论。如果ParentItemID > 0我们需要匹配ParentItemID一个评论ID,并将子评论添加到父评论列表中。

我被困的地方是,我过去只使用递归来导航文件和文件夹。这不允许我实例化一个集合并通过后续递归保留它。

在递归之外实例化列表似乎也很愚蠢,然后每次我想添加一个项目时循环遍历所有项目。

我确信这样做有一个很好的可靠模式,我只是找不到它。

4

3 回答 3

4

您可以遍历所有评论并获取每个评论的子评论:

foreach (Comment comment in comments) {
  comment.ChildComments =
    comments.Where(c => c.ParentItemID == comment.ItemID).ToList();
}

另一种性能更好的替代方法(如果需要的话)是将注释分组ParentItemID并从中创建一个Dictionary<int, List<Comment>>,然后像上面一样遍历注释并从字典中获取列表。

于 2012-08-28T22:56:16.630 回答
3

Guffa 的解决方案更漂亮,但这里有一个替代方案:

    public static List<Comment> ToTree(List<Comment> FlatCommentsList)
    {
        List<Comment> TopComments = FlatCommentsList.Where<Comment>(x => x.ParentItemID == 0).ToList();

        List<Comment> NestedComments = FlatCommentsList.Where<Comment>(x => x.ParentItemID > 0).ToList();

        List<int> IdsToRemove;

        while (NestedComments.Count > 0)
        {
            IdsToRemove = new List<int>();

            NestedComments.ForEach(x =>
            {
                Comment ParentComment = TopComments.Where<Comment>(y => y.ItemID == x.ParentItemID).SingleOrDefault<Comment>();

                if (ParentComment != null)
                {
                    ParentComment.ChildComments.Add(x);
                    IdsToRemove.Add(x.ItemID);
                }    
            });

            NestedComments.RemoveAll(x => IdsToRemove.Contains(x.ItemID));
        }

        return TopComments;
    }

它也没有递归,但它完成了它的工作。我非常喜欢递归,但我认为我们在这里不需要它。

于 2012-08-28T23:03:37.030 回答
1

可以使用 LINQ 和 分隔顶级注释和嵌套注释GroupBy

var grouped = comments.GroupBy(c => c.ParentItemId == 0);
var topLevel = grouped.Single(g => g.Key);
var nested = grouped.Single(g => !g.Key);

(这些操作的结果实际上不会被计算,直到您迭代序列或使用诸如ToList()在它们上的方法)

将嵌套评论附加到他们的父母可以像 Guffa 的方法一样完成(对于很多评论来说很慢,不使用额外的内存),或者你可以做一个经典的时空权衡(对于很多评论来说很快,需要额外的内存):

var dictionary = comments.ToDictionary(c => c.Id);
foreach (nested as comment) {
    dictionary[comment.ParentItemId].ChildComments.Add(comment);
}
于 2012-08-28T23:04:40.323 回答