递归菜单的级别顺序错误
Recursive menu is wrong level ordered
正在尝试使用 C# 构建递归菜单。我需要的菜单如下:
。客户
. . . .客户 1
. . . .客户 3
.公司
. . . .愿景
. . . . . . .简短声明
. . . .我们是谁
. . . . . . .联系我们
. . . . . . .团队
. . . . . . . . . .写信给我们
. . . . . . . . . . . . .媒体
但我得到:
. Company
. . . . Vision
. . . . Who We Are
. . . . . . . Short Statement
. . . . . . . . . . Contact Us
. . . . . . . . . . Team
. . . . . . . . . . . . . Write To Us
. . . . . . . . . . . . . . . . Media
. Clients
. . . . Client 1
. . . . Client 3
一些更正需要完成,所以我需要你的帮助:
- 菜单项应按字母顺序排列;前任。客户应该在第一位,然后是公司
- 有些项目的级别排序和缩进有误;前任。简短声明应在愿景之后和我们是谁之前
到目前为止我试过:
class Program
{
public class Node<T>
{
public T Data { get; set; }
public List<Node<T>> Children { get; set; }
public Node()
{
Children = new List<Node<T>>();
}
public List<Node<T>> LevelOrder()
{
List<Node<T>> list = new List<Node<T>>();
Queue<Node<T>> queue = new Queue<Node<T>>();
queue.Enqueue(this);
while (queue.Count != 0)
{
Node<T> temp = queue.Dequeue();
foreach (Node<T> child in temp.Children)
queue.Enqueue(child);
list.Add(temp);
}
return list;
}
public List<Node<T>> PreOrder()
{
List<Node<T>> list = new List<Node<T>>();
list.Add(this);
foreach (Node<T> child in Children)
list.AddRange(child.PreOrder());
return list;
}
public List<Node<T>> PostOrder()
{
List<Node<T>> list = new List<Node<T>>();
foreach (Node<T> child in Children)
list.AddRange(child.PreOrder());
list.Add(this);
return list;
}
}
public class Entity
{
public int id { get; set; }
public string menuName { get; set; }
public int? parentID { get; set; }
public bool isHidden { get; set; }
public string linkURL { get; set; }
}
static void Main(string[] args)
{
var data = @"ID;MenuName;ParentID;isHidden;Link
1;Company;NULL;False;/company
2;Who We Are;1;False;/company/whoweare
3;Vision;1;False;/company/vision
4;Team;2;False;/company/whoweare/team
5;Client 3;10;False;/clients/client3
6;Client 1;10;False;/clients/client1
7;Client 4;10;True;/clients/client4
8;Client 5;10;True;/clients/client5
10;Clients;NULL;False;/clients
11;Contact Us;2;False;/company/whoweare/contactus
12;Write To Us;4;False;/company/whoweare/team/writetous
13;Media;12;False;/company/whoweare/team/writetous/media
14;Short Statement;3;False;/company/vision/shortstatement";
var lines = data.Split('\n');
var rootNodes = new List<Node<Entity>>();
var childItems = new List<Entity>();
foreach (var row in lines.Skip(1))
{
var columns = row.Split(';');
var id = Convert.ToInt32(columns[0]);
var menuName = columns[1];
var parentID = ToNullableInt(columns[2]);
var isHidden = Convert.ToBoolean(columns[3]);
var linkURL = columns[4];
var entity = new Entity()
{
id = id,
menuName = menuName,
parentID = parentID,
isHidden = isHidden,
linkURL = linkURL
};
if (parentID == null)
{
rootNodes.Add(new Node<Entity>()
{
Data = entity
});
}
else
{
childItems.Add(entity);
}
}
foreach (var rootNode in rootNodes)
{
foreach (var childItem in childItems.OrderBy(a => a.parentID).ThenBy(b => b.menuName))
{
var newNode = new Node<Entity>()
{
Data = childItem
};
Insert(rootNode, newNode);
}
}
foreach (var rootNode in rootNodes)
{
var indent = 0;
var previous = rootNode;
foreach (var node in rootNode.LevelOrder())
{
if (node.Data.isHidden) continue;
if (previous.Data.parentID != node.Data.parentID)
indent++;
for (var i = 0; i < indent; i++)
Console.Write(". . . ");
Console.WriteLine(". " + node.Data.menuName);
previous = node;
}
}
}
public static void Insert(Node<Entity> rootNode, Node<Entity> targetNode)
{
foreach (var current in rootNode.LevelOrder())
{
if (current.Data.id == targetNode.Data.parentID)
{
current.Children.Add(targetNode);
return;
}
}
}
public static int? ToNullableInt(string s)
{
int i;
if (int.TryParse(s, out i)) return i;
return null;
}
}
如果您更新 PreOrder 以使用 (level, item) 的元组,例如:
public List<(int level, Node<T> item)> PreOrder(int level = 0)
{
List<(int level, Node<T> item)> list = new List<(int level, Node<T> item)>();
list.Add((level, this));
level += 1;
foreach (Node<T> child in Children)
list.AddRange(child.PreOrder(level));
return list;
}
并在您的打印部分中使用它(我还在这里添加了 menuName 的订单):
foreach (var rootNode in rootNodes.OrderBy(a => a.Data.menuName))
{
var indent = 0;
foreach (var node in rootNode.PreOrder())
{
if (node.item.Data.isHidden)
continue;
for (var i = 0; i < node.level; i++)
Console.Write(". . . ");
Console.WriteLine(". " + node.item.Data.menuName);
}
}
这将 return 菜单以您请求的格式显示。
正在尝试使用 C# 构建递归菜单。我需要的菜单如下:
。客户
. . . .客户 1
. . . .客户 3
.公司
. . . .愿景
. . . . . . .简短声明
. . . .我们是谁
. . . . . . .联系我们
. . . . . . .团队
. . . . . . . . . .写信给我们
. . . . . . . . . . . . .媒体
但我得到:
. Company
. . . . Vision
. . . . Who We Are
. . . . . . . Short Statement
. . . . . . . . . . Contact Us
. . . . . . . . . . Team
. . . . . . . . . . . . . Write To Us
. . . . . . . . . . . . . . . . Media
. Clients
. . . . Client 1
. . . . Client 3
一些更正需要完成,所以我需要你的帮助:
- 菜单项应按字母顺序排列;前任。客户应该在第一位,然后是公司
- 有些项目的级别排序和缩进有误;前任。简短声明应在愿景之后和我们是谁之前
到目前为止我试过:
class Program
{
public class Node<T>
{
public T Data { get; set; }
public List<Node<T>> Children { get; set; }
public Node()
{
Children = new List<Node<T>>();
}
public List<Node<T>> LevelOrder()
{
List<Node<T>> list = new List<Node<T>>();
Queue<Node<T>> queue = new Queue<Node<T>>();
queue.Enqueue(this);
while (queue.Count != 0)
{
Node<T> temp = queue.Dequeue();
foreach (Node<T> child in temp.Children)
queue.Enqueue(child);
list.Add(temp);
}
return list;
}
public List<Node<T>> PreOrder()
{
List<Node<T>> list = new List<Node<T>>();
list.Add(this);
foreach (Node<T> child in Children)
list.AddRange(child.PreOrder());
return list;
}
public List<Node<T>> PostOrder()
{
List<Node<T>> list = new List<Node<T>>();
foreach (Node<T> child in Children)
list.AddRange(child.PreOrder());
list.Add(this);
return list;
}
}
public class Entity
{
public int id { get; set; }
public string menuName { get; set; }
public int? parentID { get; set; }
public bool isHidden { get; set; }
public string linkURL { get; set; }
}
static void Main(string[] args)
{
var data = @"ID;MenuName;ParentID;isHidden;Link
1;Company;NULL;False;/company
2;Who We Are;1;False;/company/whoweare
3;Vision;1;False;/company/vision
4;Team;2;False;/company/whoweare/team
5;Client 3;10;False;/clients/client3
6;Client 1;10;False;/clients/client1
7;Client 4;10;True;/clients/client4
8;Client 5;10;True;/clients/client5
10;Clients;NULL;False;/clients
11;Contact Us;2;False;/company/whoweare/contactus
12;Write To Us;4;False;/company/whoweare/team/writetous
13;Media;12;False;/company/whoweare/team/writetous/media
14;Short Statement;3;False;/company/vision/shortstatement";
var lines = data.Split('\n');
var rootNodes = new List<Node<Entity>>();
var childItems = new List<Entity>();
foreach (var row in lines.Skip(1))
{
var columns = row.Split(';');
var id = Convert.ToInt32(columns[0]);
var menuName = columns[1];
var parentID = ToNullableInt(columns[2]);
var isHidden = Convert.ToBoolean(columns[3]);
var linkURL = columns[4];
var entity = new Entity()
{
id = id,
menuName = menuName,
parentID = parentID,
isHidden = isHidden,
linkURL = linkURL
};
if (parentID == null)
{
rootNodes.Add(new Node<Entity>()
{
Data = entity
});
}
else
{
childItems.Add(entity);
}
}
foreach (var rootNode in rootNodes)
{
foreach (var childItem in childItems.OrderBy(a => a.parentID).ThenBy(b => b.menuName))
{
var newNode = new Node<Entity>()
{
Data = childItem
};
Insert(rootNode, newNode);
}
}
foreach (var rootNode in rootNodes)
{
var indent = 0;
var previous = rootNode;
foreach (var node in rootNode.LevelOrder())
{
if (node.Data.isHidden) continue;
if (previous.Data.parentID != node.Data.parentID)
indent++;
for (var i = 0; i < indent; i++)
Console.Write(". . . ");
Console.WriteLine(". " + node.Data.menuName);
previous = node;
}
}
}
public static void Insert(Node<Entity> rootNode, Node<Entity> targetNode)
{
foreach (var current in rootNode.LevelOrder())
{
if (current.Data.id == targetNode.Data.parentID)
{
current.Children.Add(targetNode);
return;
}
}
}
public static int? ToNullableInt(string s)
{
int i;
if (int.TryParse(s, out i)) return i;
return null;
}
}
如果您更新 PreOrder 以使用 (level, item) 的元组,例如:
public List<(int level, Node<T> item)> PreOrder(int level = 0)
{
List<(int level, Node<T> item)> list = new List<(int level, Node<T> item)>();
list.Add((level, this));
level += 1;
foreach (Node<T> child in Children)
list.AddRange(child.PreOrder(level));
return list;
}
并在您的打印部分中使用它(我还在这里添加了 menuName 的订单):
foreach (var rootNode in rootNodes.OrderBy(a => a.Data.menuName))
{
var indent = 0;
foreach (var node in rootNode.PreOrder())
{
if (node.item.Data.isHidden)
continue;
for (var i = 0; i < node.level; i++)
Console.Write(". . . ");
Console.WriteLine(". " + node.item.Data.menuName);
}
}
这将 return 菜单以您请求的格式显示。