views:

577

answers:

5

Hey All,

Im building a Threaded Comment System for a website of mine and I ran into a problem...

I have a list PULLED FROM A DATABASE that has a ID field and a Parent ID Field. The parent ID field can be null, but the ID field will NEVER be null.

Since this will be a threaded comment system, I organize the list to where the ID is the top one, but if a parent ID exists, then it would be inserted under the ID. Then this can go on for infinity also. So the second level now also has an ID and and I want to insert any item with a parent ID of that ID under it.

For example:

---1. Blah

--------2. Blah Blah -> ParentID=1

-----------3. Blah Blah -> parentID=2

-------------- 4. Blah Blah ->parentID=3

----------- 3.Blah Blah -> parentID=2

--------2. Blah Blah -> parentID=1

I think you get the point.

So here is what I have so far...

List<comment> finalList = new List<comment>();
    for (int i = 0; i < getComments.Count(); i++)
    {
        string item = getComments[i].parentComment;
        getComments[i].threadID = 1;
        finalList.Add(getComments[i]);
        for (int ii = 0; ii < getComments.Count(); ii++)
        {
            if (getComments[ii].commentID == item)
            {
                getComments[ii].threadID = 2;
                finalList.Add(getComments[i]);
            }
        }
    }

It seems to sort it half way, but not truly... The ThreadID is of course how far it gets planted to the right.

A: 

You need a recursive function, and, based on how it looks like you're traversing the list, it would probably be better to store ID and ChildID (rather than parent ID). This way the recursive function can end a traversal when ChildID == null.

Robert C. Barth
A: 

Given that you're using the Count() extension method instead of the Count property (which is a slight inefficiency in itself; using foreach would be better to start with though) you're presumably using .NET 3.5.

I don't think I fully understand your scheme - for instance, what is there to say that the comment with threadID=4 in your diagram goes under the first threadID=3 element instead of the second?

Without knowing much in the way of details of what you're after, in general I'd consider a commenting data structure with:

  • CommentID: the ID of this entity
  • RootID: the ID of the root element for the thread (so you can fetch all comments for a thread easily)
  • ParentID: the CommentID of the parent for this comment, or null if it's the root element
  • Timestamp: Or something else which would allow the child comments within one parent to be sorted appropriately.

Given that, it would be fairly easy to work out the indentation level, if that's what you're concerned about. If that sounds useful, I can go into more details - if not, please clarify the question.

Jon Skeet
A: 

This might work:

class Program
    {
        static void Main(string[] args)
        {
            CommentCollection collection=new CommentCollection();
            Comment c1=new Comment("Blah",1,0,collection);
            Comment c2=new Comment("Blah blah",2,1,collection);
            Comment c3=new Comment("Blah blah", 3, 2, collection);
            Console.WriteLine(collection);
        }
    }
    [DebuggerDisplay("{id}-{parentId}: {text}")]
    class Comment:IEnumerable<Comment>
    {
        private readonly CommentCollection collection;
        private readonly int parentId;

        public Comment(string text, int id, int parentId, CommentCollection collection)
        {
            Id = id;
            this.parentId = parentId;
            collection.Add(this);
            this.collection = collection;
            this.text = text;
        }
        public Comment Parent
        {
            get
            {
                if (parent == null)
                {
                    parent = parentId == 0 ? null : collection[parentId];
                }
                return parent;
            }
        }

        private Comment parent;
        private readonly string text;
        public int Id{ get; private set;}
        public IEnumerator<Comment> GetEnumerator()
        {
            return collection.Where(c => c.Parent == this).GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
        public int Level
        {
            get { return Parent == null ? 0 : Parent.Level + 1; }
        }
        public override string ToString()
        {
            return Parent == null ? text : Parent + " > " + text;
        }
        public string ToString(bool tree)
        {
            if (!tree)
            {
                return ToString();
            }
            else
            {
                StringBuilder output = new StringBuilder();
                output.AppendLine(new string(' ', Level) + ToString(false));
                foreach (Comment comment in this)
                {
                    output.AppendLine(comment.ToString(true));
                }
                return output.ToString();
            }
        }
    }
    class CommentCollection:IEnumerable<Comment>
    {
        public void Add(Comment comment)
        {
            comments.Add(comment.Id,comment);
        }
        public Comment this[int id]
        {
            get { return comments[id]; }
        }
        private readonly Dictionary<int,Comment> comments=new Dictionary<int, Comment>();

        public IEnumerator<Comment> GetEnumerator()
        {
            return comments.Select(p => p.Value).GetEnumerator();
        }

        public IEnumerable<Comment> GetTopLevel()
        {
            return comments.Where(c => c.Value.Parent == null).
                Select(c => c.Value);
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
        public override string ToString()
        {
            StringBuilder output=new StringBuilder();
            foreach (Comment comment in GetTopLevel())
            {
                output.AppendLine(comment.ToString(true));
            }
            return output.ToString();
        }
    }
Øyvind Skaar
A: 

Thanks all for your help guys. I do appreciate it.

I did though, find something by a guy that wrote absolutely everything for it.

http://www.scip.be/index.php?Page=ArticlesNET23

http://www.scip.be/index.php?Page=ArticlesNET09

http://www.scip.be/index.php?Page=ArticlesNET18

Scott