问题
I want to represent a self referencing table in a text tree (like TreeView but in text). I have been working on it and I did good so far. The problem is when I go few levels deep in the tree. So far The result is this:
┌──Main Group 1
│ ├──SubGroup 1.1
│ │ ├──SubGroup 1.1.1
│ │ ├──SubGroup 1.1.2
│ │ ├──SubGroup 1.1.3
│ │ └──SubGroup 1.1.4
│ │ ├──SubGroup 1.1.4.1
│ │ └──SubGroup 1.1.4.2
│ │ │ ├──Problem group 1
│ │ │ ├──Problem group 2
│ │ │ └──Problem group 3
│ │ │ │ └──Problem group 3.1
│ ├──SubGroup 1.2
│ └──SubGroup 1.3
│ ├──SubGroup 1.3.1
│ └──SubGroup 1.3.2
└──Main Group 2
├──SubGroup 2.1
└──SubGroup 2.2
As you can see in the Problem Groups
above, the format starts to break and extra lines are showing.
The code I wrote is:
public class Group
{
public int ID { get; set; }
public int? ParentID { get; set; }
public string Name { get; set; }
}
static void Main(string[] args)
{
List<Group> groups = new List<Group>();
groups.Add(new Group { ID = 1, ParentID = null, Name = "Main Group 1" });
groups.Add(new Group { ID = 2, ParentID = 1, Name = "SubGroup 1.1" });
groups.Add(new Group { ID = 3, ParentID = 1, Name = "SubGroup 1.2" });
groups.Add(new Group { ID = 4, ParentID = 1, Name = "SubGroup 1.3" });
groups.Add(new Group { ID = 5, ParentID = null, Name = "Main Group 2" });
groups.Add(new Group { ID = 6, ParentID = 5, Name = "SubGroup 2.1" });
groups.Add(new Group { ID = 7, ParentID = 5, Name = "SubGroup 2.2" });
groups.Add(new Group { ID = 8, ParentID = 2, Name = "SubGroup 1.1.1" });
groups.Add(new Group { ID = 9, ParentID = 2, Name = "SubGroup 1.1.2" });
groups.Add(new Group { ID = 10, ParentID = 2, Name = "SubGroup 1.1.3" });
groups.Add(new Group { ID = 11, ParentID = 2, Name = "SubGroup 1.1.4" });
groups.Add(new Group { ID = 12, ParentID = 11, Name = "SubGroup 1.1.4.1" });
groups.Add(new Group { ID = 13, ParentID = 11, Name = "SubGroup 1.1.4.2" });
groups.Add(new Group { ID = 14, ParentID = 13, Name = "Problem group 1" });
groups.Add(new Group { ID = 15, ParentID = 13, Name = "Problem group 2" });
groups.Add(new Group { ID = 16, ParentID = 13, Name = "Problem group 3" });
groups.Add(new Group { ID = 17, ParentID = 16, Name = "Problem group 3.1" });
groups.Add(new Group { ID = 18, ParentID = 4, Name = "SubGroup 1.3.1" });
groups.Add(new Group { ID = 19, ParentID = 4, Name = "SubGroup 1.3.2" });
PrintGroupsTree(groups);
Console.Read();
}
static void PrintGroupsTree(List<Group> groups)
{
if (groups == null)
return;
var rootGroups = groups.Where(grp => grp.ParentID == null);
foreach (var g in rootGroups)
PrintRow(0, g, groups);
}
private static void PrintRow(int p, Group grp, List<Group> groups)
{
string leader = string.Empty;
string leaderEnd = string.Empty;
// get the root items
var rootItems = groups.Where(g => g.ParentID == null);
// find the leading character
if (grp == rootItems.First())
{
if (rootItems.Count() == 1)
leader = "─";
else
leader = "┌";
}
else if (grp == rootItems.Last())
{
leader = "└";
}
else
{
if (p == 0)
leader = "├";
else
if (rootItems.Count() == 1)
leader += " ";
else
leader = "│";
}
if (grp.ParentID == rootItems.Last().ID)
leader = " ";
// if this is a child node
if (!rootItems.Contains(grp))
{
// get the siblings of the current node (same parentID)
var itemSiblings = groups.Where(g => g.ParentID == grp.ParentID);
if (grp == itemSiblings.Last())
leaderEnd = " └";
else
leaderEnd = " ├";
}
// get the siblings of the parent item (same as parentItem.ParentID)
var parentItem = groups.Where(g => g.ID == grp.ParentID).SingleOrDefault();
var parentItemSiblings = groups.Where(g => g.ParentID == parentItem.ParentID);
if (p > 0)
{
leader += " ";
for (int i = 1; i <= p - 1; i++)
{
if (!rootItems.Contains(grp)
&& parentItem == parentItemSiblings.Last()
&& i == p - 1)
leader += " ";
else
leader += " │ ";
}
}
// write the group
string row = leader + leaderEnd + "──" + grp.Name;
Console.WriteLine(row);
// recursive calling to the childs of this item
var childGroups = groups.Where(g => g.ParentID == grp.ID);
foreach (var g in childGroups)
{
PrintRow(p + 1, g, groups);
}
}
Is there a way to represent this correctly using a better looking code?
回答1:
This is a problem that requires recursion and you are not taking full advantage of it.
static void Main(string[] args)
{
List<Group> groups = new List<Group>();
...
PrintTree(groups, "", null);
}
static void PrintTree(List<Group> allGroups, string lead, int? id)
{
var children = allGroups.Where(g => g.ParentID == id).ToList();
if (children.Count > 0)
{
int n = children.Count-1;
for (int i = 0; i < n; i++)
{
Console.WriteLine(lead + "├──" + children[i].Name);
PrintTree(allGroups, lead + "│ ", children[i].ID);
}
Console.WriteLine(lead + "└──" + children[n].Name);
PrintTree(allGroups, lead + " ", children[n].ID);
}
}
I leave fixing the very first element as an exercise.
来源:https://stackoverflow.com/questions/13070206/represent-a-self-reference-table-in-a-text-tree