NET 通用方法:把扁平数据转换为树形数据结构【表格】
1.表格文件:节点打横成一行,根节点需要关联附属信息【Remark1 / Remark2】
2.demo
[Theory] [InlineData(@"C:\Working\TestTreeNode.xlsx")] public void Run(string path) { // 节点后端 属性名集合 var nodeNameList = new List<string> { "Node1", "Node2", "Node3" }; // 最末级节点-附属信息 属性名集合 var propertyNameList = new List<string> { "Remark1", "Remark2" }; var modelList = NpoiHelper.ConvertList<TestNodeDto>(path); var dic = new List<string>(); foreach (var itemModel in modelList) { var itemKey = string.Empty; var itemLastNodeFieldName = itemModel.GetLastNodeFieldName(); for (int i = 0; i < nodeNameList.Count; i++) { // 获取 节点后端 属性名 var itemNodeName = nodeNameList[i]; // 获取 节点后端 属性值 var itemNodeValue = itemModel[itemNodeName]; if (itemNodeValue.IsNullOrWhiteSpace()) break; var propertyList = new List<string>(); // 如果是最后一个节点,则获取附属信息 if (itemLastNodeFieldName.Equals(itemNodeName)) { foreach (var itemPropertyName in propertyNameList) { propertyList.Add($"{itemPropertyName}:{itemModel[itemPropertyName]}"); } } itemKey += itemNodeValue; // 过滤重复节点 if (!dic.Contains(itemKey)) { dic.Add(itemKey); var prefix = Enumerable.Repeat("\t", i).Join(""); _testOutputHelper.WriteLine($"{prefix}{itemNodeName}:{itemNodeValue}\t{propertyList.Join("\t")}"); } } } _testOutputHelper.WriteLine("Run"); }
3.TestNodeDto
/// <summary> /// 测试树形节点 实体 /// </summary> public class TestNodeDto { public string Code { get; set; } [DisplayName("Node1")] public string Node1 { get; set; } [DisplayName("Node2")] public string Node2 { get; set; } [DisplayName("Node3")] public string Node3 { get; set; } [DisplayName("Remark1")] public string Remark1 { get; set; } [DisplayName("Remark2")] public string Remark2 { get; set; } /// <summary> /// 获取最后一个节点字段名 /// </summary> /// <returns></returns> public string GetLastNodeFieldName() { // 从最后一个子节点往根节点判断,只要任意节点有值,则为 最后一个节点 if (!Node3.IsNullOrWhiteSpace()) return nameof(Node3); if (!Node2.IsNullOrWhiteSpace()) return nameof(Node2); if (!Node1.IsNullOrWhiteSpace()) return nameof(Node1); return string.Empty; } public string this[string fieldName] { get { switch (fieldName) { case nameof(Node1): return Node1; case nameof(Node2): return Node2; case nameof(Node3): return Node3; case nameof(Remark1): return Remark1; case nameof(Remark2): return Remark2; default: return string.Empty; } } } }
4.输出结果
Node1:Lv0 Node2:Lv0-1 Node3:Lv0-1-1 Remark1:附属信息1:Lv0-1-1 Remark2:附属信息2:Lv0-1-1 Node3:Lv0-1-2 Remark1:附属信息1:Lv0-1-2 Remark2:附属信息2:Lv0-1-2 Node3:Lv0-1-3 Remark1:附属信息1:Lv0-1-3 Remark2:附属信息2:Lv0-1-3 Node3:Lv0-1-4 Remark1:附属信息1:Lv0-1-4 Remark2:附属信息2:Lv0-1-4 Node3:Lv0-1-5 Remark1:附属信息1:Lv0-1-5 Remark2:附属信息2:Lv0-1-5 Node2:Lv0-2 Node3:Lv0-2-1 Remark1:附属信息1:Lv0-2-1 Remark2:附属信息2:Lv0-2-1 Node3:Lv0-2-2 Remark1:附属信息1:Lv0-2-2 Remark2:附属信息2:Lv0-2-2 Node3:Lv0-2-3 Remark1:附属信息1:Lv0-2-3 Remark2:附属信息2:Lv0-2-3 Node2:Lv0-3 Remark1:附属信息1:Lv0-3 Remark2:附属信息2:Lv0-3 Node2:Lv0-5 Remark1:附属信息1:Lv0-5 Remark2:附属信息2:Lv0-5 Node1:Lv1 Node2:Lv1-1 Node3:Lv1-1-1 Remark1:附属信息1:Lv1-1-1 Remark2:附属信息2:Lv1-1-1 Node2:Lv1-2 Remark1:附属信息1:Lv1-2 Remark2:附属信息2:Lv1-2 Node2:Lv1-3 Remark1:附属信息1:Lv1-3 Remark2:附属信息2:Lv1-3