まず、ツリーを作ってから、ルートからリーフまで再帰的に降ります。
class Message {
public Message(int message_id, string text, int? parent_message_id) {
Debug.Assert(message_id < int.MaxValue);
MessageID = message_id;
ParentMessageID = parent_message_id;
Text = text;
}
public readonly int MessageID;
public readonly string Text;
public readonly int? ParentMessageID;
public static IEnumerable<Message> OrderByHierarchy(IEnumerable<Message> messages) {
// Key: ParentMessageID (null substituted with int.MaxValue).
// Value: All messages sharing this parent.
var dict = messages.GroupBy(m => m.ParentMessageID ?? int.MaxValue).ToDictionary(grouping => grouping.Key);
// For each root, recursively traverse its children.
return dict[int.MaxValue].SelectMany(root => RecursiveDescent(dict, root));
}
static IEnumerable<Message> RecursiveDescent(Dictionary<int, IGrouping<int, Message>> dict, Message parent) {
yield return parent;
IGrouping<int, Message> children;
if (dict.TryGetValue(parent.MessageID, out children))
foreach (var child in children)
foreach (var descendent in RecursiveDescent(dict, child))
yield return descendent;
}
public override string ToString() {
return string.Format("{0} | {1} | {2}", MessageID, Text, ParentMessageID == null ? "null" : Convert.ToString(ParentMessageID));
}
}
class Program {
static void Main(string[] args) {
var messages = new[] {
new Message(1, "Text 1", null),
new Message(2, "Reply to Text 1", 1),
new Message(3, "Reply to Text 1 #2", 1),
new Message(4, "Reply to reply to text 1", 2),
};
foreach (var m in Message.OrderByHierarchy(messages))
Console.WriteLine(m);
}
}
これは、出力します。これを行うには多くの方法が一つでここにありますが、SQL ServerのCTE(共通テーブル式)で
1 | Text 1 | null
2 | Reply to Text 1 | 1
4 | Reply to reply to text 1 | 2
3 | Reply to Text 1 #2 | 1
:
これは私の出力を与えますか?なぜ4は3の前に来るのですか? – BrokenGlass
ソートメッセージに返信する(ParentMessageIDを参照) – John
返信件数でソートしますか?それでも私は4が3の前に来る理由を教えていません。 – BrokenGlass