我们目前正在收到具有可选父帐户 ID 的帐户列表。当摄取数据时,我们意识到父子关系并不像我们想象的那么简单。我们发现许多层次结构的深度为 3-4 级,有时甚至达到 7 级。
我们正在寻找一种方法,将源帐户数据转换为具有子记录列表的对象,并且这些子记录可以拥有子记录,依此类推。
public class AccountSourceData
{
public int Id { get; set; }
public string Name { get; set; }
public int? ParentId { get; set; }
}
public class AccountTransformedData
{
public int Id { get; set; }
public string Name { get; set; }
public List<AccountTransformedData> ChildAccounts { get; set;}
}
public List<AccountTransformedData> TransformAccountData(List<AccountSourceData> srcAccounts)
{
List<AccountTransformedData> accounts = new List<AccountTransformedData>();
foreach (var parentAccount in srcAccounts.Where(t => !t.ParentId.HasValue))
{
....
..
....
}
return accounts;
}
试试这个:
public class AccountManager
{
public List<HierarchyData> PopulateHierarchy( List<AccountRow> dataSource)
{
var topLevelItems = dataSource
.Where(x => x.ParentId == null)
.Select(x => new HierarchyData
{
Id = x.Id,
Name = x.Name,
ChildAccounts = []
}).ToList();
foreach (var item in topLevelItems)
{
AddSubItems(item, dataSource);
}
return topLevelItems;
}
private static void AddSubItems(HierarchyData item, List<AccountRow> sourceData)
{
var children = sourceData
.Where(x => x.ParentId == item.Id)
.Select(x => new HierarchyData
{
Id = x.Id,
Name = x.Name,
ChildAccounts = []
}).ToList();
item.ChildAccounts.AddRange(children);
//add the children recursively
foreach (var child in children)
{
AddSubItems(child, sourceData);
}
}
}
然后你就可以像这样简单地使用它:
var hierarchy = new AccountManager().PopulateHierarchy(data);
假设您需要您的方法返回的是:一个新列表,其中每个原始
AccountTransformedData
都有一个 AccountSourceData
类型的条目(不是任何类型的图形对象),但每个新元素都有正确的子元素填充其他元素上对应的 ParentId
。
这是实现这一目标的一种简单方法:
static List<AccountTransformedData> TransformAccountData(List<AccountSourceData> srcAccounts) {
var accounts = srcAccounts.Select(a => new AccountTransformedData { Id = a.Id, Name = a.Name, ChildAccounts = [] }).ToList();
foreach (var srcAccount in srcAccounts) {
if (srcAccount is { Id: int childId, ParentId: int parentId }) {
var child = accounts.Find(a => a.Id == childId);
var parent = accounts.Find(a => a.Id == parentId);
parent.ChildAccounts.Add(child);
}
}
return accounts;
}
这是一些测试数据:
static void Main(string[] args) {
var srcAccounts = new List<AccountSourceData> {
new() { Id = 0, Name = "Linda" },
new() { Id = 1, Name = "Mike", ParentId = 3 },
new() { Id = 2, Name = "Prasana", ParentId = 3 },
new() { Id = 3, Name = "Li", ParentId = 5 },
new() { Id = 4, Name = "Cameron" },
new() { Id = 5, Name = "Solange", ParentId = 4 },
new() { Id = 6, Name = "Giovanni" },
new() { Id = 7, Name = "Brianna", ParentId = 6 },
new() { Id = 8, Name = "Tyson" },
new() { Id = 9, Name = "Anna", ParentId = 8 },
new() { Id = 10, Name = "Saul", ParentId = 1 },
new() { Id = 11, Name = "Bob", ParentId = 4 },
new() { Id = 12, Name = "Aldebaran", ParentId = 6 },
};
var transfAccounts = TransformAccountData(srcAccounts);
foreach (var account in transfAccounts)
Console.WriteLine($"{account.Name}'s children: {string.Join(", ", account.ChildAccounts.Select(c => c.Name))}");
将会输出:
琳达的孩子们:
迈克的孩子:索尔
Prasana 的孩子们:
李的孩子:Mike、Prasana
卡梅伦的孩子:索兰吉、鲍勃
索兰吉的孩子:Li
乔瓦尼的孩子:布丽安娜、毕宿五
布莱恩娜的孩子们:
泰森的孩子:安娜
安娜的孩子们:
扫罗的孩子们:
鲍勃的孩子们:
毕宿五的孩子们:
注意:上面的实现对每个元素的完整列表进行两次迭代,并且仅在列表不大时才有效。如果您期望一个大列表,那么列表不是适合您的数据结构,请考虑哈希图或树。