在 C# 中,如何将记录列表转换为无限数量的层次结构级别?

问题描述 投票:0回答:2

我们目前正在收到具有可选父帐户 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;
}
c# linq .net-core
2个回答
0
投票

试试这个:

 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);

0
投票

假设您需要您的方法返回的是:一个新列表,其中每个原始

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
乔瓦尼的孩子:布丽安娜、毕宿五
布莱恩娜的孩子们:
泰森的孩子:安娜
安娜的孩子们:
扫罗的孩子们:
鲍勃的孩子们:
毕宿五的孩子们:


注意:上面的实现对每个元素的完整列表进行两次迭代,并且仅在列表不大时才有效。如果您期望一个大列表,那么列表不是适合您的数据结构,请考虑哈希图或树。

© www.soinside.com 2019 - 2024. All rights reserved.