问题描述:
一个List<T>, T 的基本定义如下Data,要求实现按照层次结构排序,即排序结果如下:
L1
L1.1
L1.1.1
L1.1.3
L1.2
L1.2.1
L1.2.2
L1.3
L4
L4.1
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TestProject
{
public class Data
{
public Data()
{
}
public Data(string id ,string parentId,string name)
{
Id = id;
ParentId = parentId;
Name = name;
}
public string Id
{
get;
set;
}
public string Name
{
get;
set;
}
public string ParentId
{
get;
set;
}
}
}
一个简单的实现是:通过计算各个list Item的 nodepath 来实现, 为了简单,增加了一个Path属性,如果不想修改原来Data定义,可以投影出一个新的对象来。
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections.Generic;
using System.Linq;
namespace TestProject
{
[TestClass]
public class UnitTest1
{
private readonly Random _rng = new Random();
private const string _chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
[TestMethod]
public void TestMethod1()
{
List<Data> list = GenerateData();
bool allUnique= list.TrueForAll(p=>list.Count(c=>c.Id ==p.Id)==1 );
Console.WriteLine("all id unique!");
list.ForEach(p => GetDept(list, p));
//foreach (var item in list)
//{
// Console.WriteLine("id:{0} name :{2} ,depth:{1}", item.Id, item.Depth,item.Name);
//}
Console.WriteLine();
Console.WriteLine("======orginal with node path==============");
var roots = list.FindAll(p => string.IsNullOrEmpty(p.ParentId));
//计算Node Path
roots.ForEach(p => CreateNodePath(p, string.Empty, list));
foreach (var item in list)
{
Console.WriteLine("id:{0} ,depth:{1},path ={2} name = {3}", item.Id, item.Depth, item.Path, item.Name);
}
Console.WriteLine();
Console.WriteLine("shuffled");
// 把list 以随机顺序排列
Shuffle<Data>(list);
foreach (var item in list)
{
Console.WriteLine("id:{0} ,depth:{1},path ={2} name = {3}", item.Id, item.Depth, item.Path, item.Name);
}
Console.WriteLine();
Console.WriteLine("after sort by depth====");
//按层次排序
list.Sort((p1, p2) => string.Compare(p1.Path, p2.Path));
foreach (var item in list)
{
Console.WriteLine("id:{0} ,depth:{1},path ={2} name = {3}", item.Id, item.Depth, item.Path, item.Name);
}
return;
}
int GetDept(List<Data> list, Data data)
{
if (data == null)
return -1;
if (data.ParentId == null)
{
data.Depth = 1;
//data.Path = data.Id;
//return 1;
}
else
{
int depth = GetDept(list, list.FirstOrDefault(p => p.Id == data.ParentId));
data.Depth= depth + 1;
// data.Path = string.Compare("{0}.1", data.Depth);
}
return data.Depth;
}
void CreateNodePath(Data rootNode ,string startPath,List<Data> list)
{
rootNode.Path = string.Format("{0}.{1}", startPath, rootNode.Id);
startPath = rootNode.Path;
var subnodes = list.FindAll(p => p.ParentId == rootNode.Id);
foreach (var sub in subnodes)
{
CreateNodePath(sub, startPath, list);
}
}
List<Data> GenerateData()
{
var l1 = new Data(RandomString(8), null, RandomString(8) + "(1)");
var l1_1 = new Data(RandomString(8), l1.Id, RandomString(8) + "(1.1)");
var l1_2 = new Data(RandomString(8), l1.Id, RandomString(8) + "(1.2)");
///
var l2 = new Data(RandomString(8), null, RandomString(8) + "(2)");
var l2_1 = new Data(RandomString(8), l2.Id, RandomString(8) + "(2.1)");
var l2_2 = new Data(RandomString(8), l2.Id, RandomString(8) + "(2.2)");
var l_2_2_1 = new Data(RandomString(8), l2_2.Id, RandomString(8) + "(2.2.1)");
var l_2_2_2= new Data(RandomString(8), l2_2.Id, RandomString(8) + "(2.2.2)");
var l2_3 = new Data(RandomString(8), l2.Id, RandomString(8) + "(2.3)");
var l3 = new Data(RandomString(8), null, RandomString(8) + "(3)");
var l3_1 = new Data(RandomString(8), l3.Id, RandomString(8) + "(3.1)");
var l4 = new Data(RandomString(8), null, RandomString(8) + "(4)");
///
var l5 = new Data(RandomString(8), null, RandomString(8) + "(5)");
var l5_1 = new Data(RandomString(8), l5.Id, RandomString(8) + "(5.1)");
var l5_1_1 = new Data(RandomString(8), l5_1.Id, RandomString(8) + "(5.1.1)");
var l5_1_2 = new Data(RandomString(8), l5_1.Id, RandomString(8) + "(5.1.2)");
var l5_2 = new Data(RandomString(8), l5.Id, RandomString(8) + "(5.2)");
var list = new List<Data>
{
l1,
l1_1,
l1_2
,l2,
l2_1,
l2_2,
l_2_2_1,
l_2_2_2,
l2_3
, l3
,l3_1,
l4
,l5
,l5_1
,l5_1_1
,l5_1_2
,l5_2
};
return list;
}
private string RandomString(int size)
{
char[] buffer = new char[size];
for (int i = 0; i < size; i++)
{
buffer[i] = _chars[_rng.Next(_chars.Length)];
}
return new string(buffer);
}
public static void Shuffle<T>( IList<T> list)
{
int n = list.Count;
Random rnd = new Random();
while (n > 1)
{
int k = (rnd.Next(0, n) % n);
n--;
T value = list[k];
list[k] = list[n];
list[n] = value;
}
}
}
}
结果如下: